﻿using System;
using System.Collections.Generic;
using System.Linq;

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Metadata;

using Fes.Xrm.Methods;
using System.ServiceModel;
using System.Security.Permissions;
using GFA.SP.Plugins.WCFGFA;


/// <summary>
/// Autor: Julio Esquivel 
/// Fecha Go Live - 9 de Mayo del 2014 (Ambiente Productivo GFA Admin - 51334340-C8FA-E211-B833-0050568C6FB3)
/// Fecha de modificación: 3 Noviembre 2014 - Se agrega funcionalidad para Cancelar Bono de Promociones por Acumulación, en caso de Cancelación de Viaje
/// </summary>
namespace GFA.SP.Plugins
{
    /// <summary>
    /// Autor: Julio Esquivel 
    /// Fecha Enero 2014
    /// Descripción: Se genera Consecutivo en la Creación, dependiendo del Tipo de Socio
    /// Mensaje: Create; Entidad: Contact; Pipeline: Post-Operation; Execution Order: 1
    /// Descripción: Se genera Consecutivo en la actualización del Socio, al cambia de Kid a Plus y en el Cambio de Solicitud Pendiente a Alta
    /// Mensaje: Update; Attributes: statuscode, gfa_tipodesocioid; Entidad: Contact; Pipeline: Post-Operation; Execution Order: 2  
    /// Mensaje: Create; Entidad: account; Pipeline: Post-Operation; Execution Order: 2
    /// Mensaje: Update; Attributes: statuscode; Entidad: account; Pipeline: Post-Operation; Execution Order: 2  
    /// Versión 1.0
    /// </summary>
    public class GenNumTarjetaIdNip : IPlugin
    {
        // Variables Publicas
        public string NumTar = string.Empty;
        public string Nip = string.Empty;
        public string GfaIdSocio = string.Empty;

        public Entity Entidad = null;
        public IOrganizationService Servicio;
        public List<string> RazonEstadoPermitidas = new List<string>(new string[] { "223060000", "223060003", "223060002" }); //Corpo-Alta; SP-Alta; SP-Alta por Cambio de Categoria        
        public List<string> MediosNoPermitidos = new List<string>(new string[] { "FB", "IN" }); //FACEBOOK Y PORTAL WEB // Para no establecer medio de inscripción por área      

        public void Execute(IServiceProvider ProveedorServicio)
        {
            try
            {
                //Obtenemos el Contexto de ejecución del Plugin
                IPluginExecutionContext Contexto = (IPluginExecutionContext)ProveedorServicio.GetService(typeof(IPluginExecutionContext));

                // Validamos que exista un objeto de tipo Entity
                ValidaContexto(Contexto, ProveedorServicio);
                // Consumimos el Servicio de Organización   // Administrador CRM GFA PROD      
                Servicio = OrganizationServiceCrm.ObtenerServicioUser(new Guid("51334340-C8FA-E211-B833-0050568C6FB3"), ProveedorServicio);
                // Pasamos Objeto de Servicio a los métodos FesXrm
                MetodosFes Inicializa = new MetodosFes(Servicio);

                // Validamos que la entidad realmente sean Socios Siempre Plus
                if (Contexto.PrimaryEntityName.Equals("contact"))
                {
                    // Recuperamos los datos del registro por el GUID de la Cuenta
                    Entity Socio = Servicio.Retrieve("contact", Contexto.PrimaryEntityId, new ColumnSet("gfa_tipodesocioid", "gfa_mediodeinscripcionid", "statuscode", "gfa_motivo", "ownerid"));
                    // Se genera Id de Socio
                    GfaIdSocio = GeneraIdSocio(Entidad, Socio, Contexto.PrimaryEntityName, Contexto.PrimaryEntityId, true);
                    // Se genera Num de Tarjeta
                    NumTar = GeneraNumTarjeta(Socio);
                    // Se genera NIP
                    Nip = GeneraNip();
                    // Se actualiza Medio de Inscripción en base al Usuario que ejecuta el Plugin
                    ActualizaMedioInscripcionFecha(Contexto.UserId, Contexto.PrimaryEntityId, Socio, true);
                    //VerificaPromocionesVigentes(Contexto.PrimaryEntityId, Socio, true);  **** ANTERIOR, SÓLO PARA PRESENTACION
                }

                if (Contexto.PrimaryEntityName.Equals("account"))
                {
                    // Recuperamos los datos del registro por el GUID de la Cuenta
                    Entity SocioCorp = Servicio.Retrieve("account", Contexto.PrimaryEntityId, new ColumnSet("gfa_tipodesocioid", "gfa_mediodeinscripcionid", "statuscode", "gfa_motivo", "ownerid"));

                    // Sólo si l tipo de Socio es "CO", hacemos el proceso
                    if (MetodosFes.EsTipoSocioCorporativo(SocioCorp))
                    {
                        // Se genera Id de Socio
                        GfaIdSocio = GeneraIdSocio(Entidad, SocioCorp, Contexto.PrimaryEntityName, Contexto.PrimaryEntityId, false);
                        // Se genera Num de Tarjeta
                        NumTar = GeneraNumTarjeta(SocioCorp);
                        // Se genera NIP
                        Nip = GeneraNip();
                        // Se actualiza Medio de Inscripción en base al Usuario que ejecuta el Plugin
                        ActualizaMedioInscripcionFecha(Contexto.UserId, Contexto.PrimaryEntityId, SocioCorp, false);
                        // Se verifican Promociones Vigentes***  
                        //VerificaPromocionesVigentes(Contexto.PrimaryEntityId, SocioCorp, false); //**** ANTERIOR, SOLO PARA PRESENTACIONES
                    }
                }

            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw new InvalidPluginExecutionException("Siempre Plus ERROR Alta Socio. " + ex.Message);
            }
        }

        #region # Método de validación del Contexto que recibe el Plugin
        private Entity ValidaContexto(IPluginExecutionContext Context, IServiceProvider Prov_Servicio)
        {
            if (Context.InputParameters.Contains("Target") && Context.InputParameters["Target"] is Entity)
                Entidad = (Entity)Context.InputParameters["Target"];

            return Entidad;
        }
        #endregion

        #region # Método para generar ID Socio
        private string GeneraIdSocio(Entity EntidadPlugin, Entity Socio, string NombreEntidadPlugin, Guid SocioId, bool EsPlus)
        {
            #region Variables Locales
            Guid TipoSocioId = Guid.Empty;
            Guid SecNumId = Guid.Empty;

            int RazonEstado = 0;

            string ConsecutivoSocio = string.Empty;

            string Prefijo = string.Empty;
            string Mascara = string.Empty;

            string NumConsecutivo_cad = "0";
            int NumConsecutivo_int = 0;

            string CampoConsecutivoNuevo = string.Empty;
            string CampoConsecutivoExist = string.Empty;
            bool ExisteCampo = false;

            OptionSetValue Separador_Op = new OptionSetValue();
            string Separador = string.Empty;

            string NombreCampoConsecutivo = string.Empty;

            EntityCollection SecNumRes = null;
            string[] ColumnasSecNum = new string[] { "fes_secuencianumericaid", "fes_nombrelogicoentidad", "fes_prefijo", "fes_separador", "fes_mascara", "fes_consecutivo", "fes_nombrecamponuevo", "fes_existecampo", "fes_nombrelogicoatributo" };
            #endregion

            #region Proceso General
            // Validamos si el resultados trae el campo de razón para el estado
            if (MetodosFes.ExisteAtributo("statuscode", Socio))
                RazonEstado = ((OptionSetValue)Socio.Attributes["statuscode"]).Value;

            // Se valida si la razón para el estado está dentro de las permitidas /*Socio Corporativo y Socios Plus*/
            if (RazonEstadoPermitidas.Contains(RazonEstado.ToString()))
            {
                #region Recuperacion de los datos de las entidades participantes en el consecutivo
                ///*Si es Socio Plus, entonces recuperamos consecutivo de Contactos y su tipo de Socio Id*/
                //if (EsPlus)
                //{
                //    // Validamos si el resultados trae el campo de tipo de Socio
                //    if (MetodosFes.ExisteAtributo("gfa_tipodesocioid", Socio))
                //        TipoSocioId = ((EntityReference)Socio.Attributes["gfa_tipodesocioid"]).Id;

                //    if (TipoSocioId != Guid.Empty)
                //        SecNumRes = MetodosFes.RecuperacionMultiple("fes_secuencianumerica", ColumnasSecNum, "fes_nombrelogicoentidad", NombreEntidadPlugin, "gfa_tipodesocio", TipoSocioId.ToString(), "statecode", "Active");
                //}
                //else /*Si es Socio Corporativo, se realiza la construccion del consecutivo de manera normal */
                //{
                //    SecNumRes = MetodosFes.RecuperacionMultiple("fes_secuencianumerica", ColumnasSecNum, "fes_nombrelogicoentidad", NombreEntidadPlugin, "statecode", "Active");
                //}

                /* Inicia JER 13 Marzo 2014: Corrección, el ID de Socio no distinguirá Tipo, será uno para todos */
                SecNumRes = MetodosFes.RecuperacionMultiple("fes_secuencianumerica", ColumnasSecNum, "fes_nombrelogicoentidad", NombreEntidadPlugin, "statecode", "Active");
                /* Termina JER 13 Marzo 2014*/

                #endregion

                #region Proceso de recuperación de la configuración
                //Si hay registros en la entidad de Secuencias Numericas
                if (SecNumRes != null)
                {
                    if (SecNumRes.Entities.Count > 0)
                    {
                        foreach (Entity SecNums in SecNumRes.Entities)
                        {
                            if (MetodosFes.ExisteAtributo("fes_secuencianumericaid", SecNums))
                                SecNumId = (Guid)SecNums.Attributes["fes_secuencianumericaid"];

                            if (MetodosFes.ExisteAtributo("fes_separador", SecNums))
                            {
                                Separador_Op = (OptionSetValue)SecNums.Attributes["fes_separador"];
                                // Para recuperar las Opciones de LIsta seleccionadas del Separador, se hace una llamada a los metadatos
                                Separador = MetodosFes.RecuperaOpcionListaTexto("fes_secuencianumerica", "fes_separador", Separador_Op);
                            }

                            /* Adecuacion FES para tomar en cuenta campo nuevo o existente 02-MAYO-2013*/
                            if (MetodosFes.ExisteAtributo("fes_existecampo", SecNums))
                                ExisteCampo = (bool)SecNums.Attributes["fes_existecampo"];

                            /* Si se eligió Sí en ¿Es un campo nuevo de consecutivo? Se obtiene el nombre de dicho campo nuevo */
                            if (MetodosFes.ExisteAtributo("fes_nombrecamponuevo", SecNums))
                                CampoConsecutivoNuevo = "gfa_" + (string)SecNums.Attributes["fes_nombrecamponuevo"];

                            /* Campo que contiene el nombre del atributo seleccionado (en caso de ser existente)*/
                            if (MetodosFes.ExisteAtributo("fes_nombrelogicoatributo", SecNums))
                                CampoConsecutivoExist = (string)SecNums.Attributes["fes_nombrelogicoatributo"];

                            if (MetodosFes.ExisteAtributo("fes_prefijo", SecNums))
                                Prefijo = (string)SecNums.Attributes["fes_prefijo"];

                            if (MetodosFes.ExisteAtributo("fes_mascara", SecNums))
                                Mascara = (string)SecNums.Attributes["fes_mascara"];

                            if (MetodosFes.ExisteAtributo("fes_consecutivo", SecNums))
                                NumConsecutivo_cad = (string)SecNums.Attributes["fes_consecutivo"];
                        }
                    }
                    else
                        throw new InvalidPluginExecutionException("Secuencias Númericas ERROR: No existen datos de Configuración.");
                }
                else
                    throw new InvalidPluginExecutionException("Secuencias Númericas ERROR: No existen datos de Configuración.");
                #endregion

                #region Validación del Nombre del Campo Nuevo o Existente
                /* Se valida si es un campo nuevo, entonces se toma el nombre especificado en el atributo correspondiente */
                if (!ExisteCampo)
                    NombreCampoConsecutivo = CampoConsecutivoNuevo;
                else
                    /*Si es uno existente, entonces se toma el nombre especificado en el atributo correspondiente */
                    NombreCampoConsecutivo = CampoConsecutivoExist;

                #endregion

                #region Tratamiento de Número Consecutivo
                Mascara = Mascara.Replace("#", "0");
                NumConsecutivo_int = int.Parse(NumConsecutivo_cad) + 1;

                //Tratamiento de la cadena Consecutivo General
                ConsecutivoSocio = Prefijo + Separador + Mascara.Substring(0, Mascara.Length - NumConsecutivo_int.ToString().Length) + NumConsecutivo_int.ToString();

                #endregion

                #region Proceso de actualizacion de Entidades para Configuración del Consecutivo y La entidad en Contexto              
                //if (EsPlus)
                //{
                //    /*Se agrega el consecutivo general en el contexto del Plugin*/
                //    ActualizaEntidad("contact", SocioId.ToString(), NombreCampoConsecutivo, ConsecutivoSocio.ToString());
                //}
                //else
                //{
                //    /*Se agrega el consecutivo general en el contexto del Plugin*/
                //    ActualizaEntidad("account", SocioId.ToString(), NombreCampoConsecutivo, ConsecutivoSocio.ToString());
                //}
                #endregion

                /*Se utiliza el metodo de Organizacion UPDATE para actualizar el ultimo número del Consecutivo en el registro de Secuencias Numericas*/
                ActualizaEntidad("fes_secuencianumerica", SecNumId, "fes_consecutivo", NumConsecutivo_int.ToString());

                /*Se utiliza el metodo de Organizacion UPDATE para actualizar la vista previa en el registro de configuración de Secuencias Numericas*/
                ActualizaEntidad("fes_secuencianumerica", SecNumId, "fes_vistaprevia", ConsecutivoSocio.ToString());
            }
            #endregion
            return ConsecutivoSocio;
        }
        #endregion

        #region # Método de Actualización (Organización)
        public void ActualizaEntidad(string EntidadQueSeActualiza, Guid IdEntidadQueSeActualiza, string CampoQueSeActualiza, string DatoActualizar)
        {
            Entity updateEntity = new Entity(EntidadQueSeActualiza);
            updateEntity.Attributes[EntidadQueSeActualiza + "id"] = IdEntidadQueSeActualiza;
            updateEntity[CampoQueSeActualiza] = DatoActualizar;
            Servicio.Update(updateEntity);
        }
        #endregion

        #region # Método para generar Número de Tarjeta con Socio
        private string GeneraNumTarjeta(Entity SocioContext)
        {
            #region Generación de Prueba
            /*Random rand = new Random((int)DateTime.Now.Ticks);
            int RandomNumber;
            RandomNumber = rand.Next(100000000, 999999999);
            return RandomNumber.ToString();*/
            #endregion

            // Variables locales
            string uno = string.Empty;
            string dos = string.Empty;
            string tres = string.Empty;
            string temp = string.Empty;
            string valor = string.Empty;
            string NumTarjeta = string.Empty;
            string idconsec = string.Empty;

            int FolioConsec = 0;
            int FolioNuevo = 0;

            /*Dato de fecha hora actual */
            DateTime FechaHoy = DateTime.Now;
            string FechaCadena = FechaHoy.ToString("dd/MM/yyyy");

            // Se copian en una variable llamada "dos", los dos dígitos desde la posición 9  
            // .. que corresponden a los dos últimos dígitos del año
            dos = FechaCadena.Substring(8);

            // Obtenemos el GUID del Tipo de Socio, en base al objeto que recibe el Plugin
            Guid TipoSocioId = MetodosFes.ExisteAtributo("gfa_tipodesocioid", SocioContext) ? ((EntityReference)SocioContext["gfa_tipodesocioid"]).Id : Guid.Empty;

            // Se obtiene el prefijo de Tarjeta por el tipo de Socio
            Entity TipoSocio = Servicio.Retrieve("gfa_tiposocios", TipoSocioId, new ColumnSet("gfa_tiposociosid", "gfa_prefijotarjeta"));
            uno = MetodosFes.ExisteAtributo("gfa_prefijotarjeta", TipoSocio) ? TipoSocio["gfa_prefijotarjeta"].ToString() : "";

            // Tratamiento del Folio consecutivo, existente en CRM            
            string[] ColumSet = new string[] { "gfa_foliosid", "gfa_folio" };
            EntityCollection Consecutivocol = MetodosFes.RecuperacionMultiple("gfa_folios", ColumSet, "gfa_clavetarjeta", "NT1");
            foreach (Entity Folio in Consecutivocol.Entities)
            {
                FolioConsec = (int)Folio["gfa_folio"];
                idconsec = Folio["gfa_foliosid"].ToString();
                break;
            }

            FolioNuevo = FolioConsec + 1;
            tres = (FolioNuevo).ToString();
            temp = uno + dos + tres;
            // Digito verificador del algoritmo de Luhn
            //valor = MetodosFes.DigitoVerificadorLuhn(temp); * JER 07 MAYO SE VA TERMPORALMENTE POR PETICION DE GFA

            NumTarjeta = temp; //+ valor; * JER 07 MAYO SE VA TERMPORALMENTE POR PETICION DE GFA
            //bool respuesta = MetodosFes.ValidaDigitoLuhn(NumTarjeta); * JER 07 MAYO SE VA TERMPORALMENTE POR PETICION DE GFA

            //if (respuesta)
            //{
                Entity Consecutivo = new Entity("gfa_folios");
                Consecutivo["gfa_foliosid"] = new Guid(idconsec);
                Consecutivo["gfa_folio"] = FolioNuevo;
                Servicio.Update(Consecutivo);
                return NumTarjeta;
            //}
            //else
            //{
              //  return "";
            //}
        }
        #endregion

        #region # Método para generar NIP
        private string GeneraNip()
        {
            Random rand = new Random((int)DateTime.Now.Ticks);
            int RandomNumber;
            RandomNumber = rand.Next(1000, 9999);

            return RandomNumber.ToString();
        }
        #endregion

        #region # Método para Colocar Medio de Inscripción en Base Al Usuario
        private void ActualizaMedioInscripcionFecha(Guid Usr, Guid IdSocio, Entity Soc, bool EsSocioPlus)
        {
            Guid MedioId = Guid.Empty;
            string MedioClave = string.Empty;
            string MotivoCambio = "";

            Guid MedioIdArea = Guid.Empty;
            int AreaValue = 0;
            int EstadoSocio = 0;
          
            if (MetodosFes.ExisteAtributo("statuscode", Soc))
                EstadoSocio = ((OptionSetValue)Soc.Attributes["statuscode"]).Value;

            if (MetodosFes.ExisteAtributo("gfa_mediodeinscripcionid", Soc))
                MedioId = ((EntityReference)Soc.Attributes["gfa_mediodeinscripcionid"]).Id;          

            /* Si el Estado del Socio es Alta o Alta por Cambio de Tipo, Alta Corporativo */
            if (RazonEstadoPermitidas.Contains(EstadoSocio.ToString()))
            {
                /*Recuperamos la información del Usuario */                
                Entity Usuario = Servicio.Retrieve("systemuser", Usr, new ColumnSet("gfa_area"));

                /*Realizamos el tratamiento para identificar el Area a la que pertenece*/
                if (MetodosFes.ExisteAtributo("gfa_area", Usuario))
                {
                    AreaValue = ((OptionSetValue)Usuario.Attributes["gfa_area"]).Value;
                    MedioIdArea = MetodosFes.RecuperaGuidMedioporArea(AreaValue);

                    Entity ActSocio;

                    /*Si es Socio Plus */
                    if (EsSocioPlus)
                    {
                        ActSocio = new Entity("contact");
                        ActSocio.Attributes["contactid"] = IdSocio;
                    }
                    else // En caso de que sea Corporativo
                    {
                        ActSocio = new Entity("account");
                        ActSocio.Attributes["accountid"] = IdSocio;
                    }

                    /*JER 13-Marzo-2014 - Si el medio de inscripción es FACEBOOK o PORTAL WEB, no aplica actualización de medio de inscripción en base al área */
                    Entity Medio = Servicio.Retrieve("gfa_catalogodemedios", MedioId, new ColumnSet("gfa_id"));

                    if (MetodosFes.ExisteAtributo("gfa_id", Medio))
                    {
                        // Recuperamos la clave del Medio actual
                        MedioClave = (string)Medio.Attributes["gfa_id"];
                        // Si el medio actual del Socio no es PORTAL WEB o FACEBOOK, se permite actualizar medio por área a la que pertenece el usuario
                        if (!MediosNoPermitidos.Contains(MedioClave))
                        {
                            /*Si hay respuesta del Medio encontrado en el Usuario*/
                            if (MedioIdArea != Guid.Empty)
                                ActSocio.Attributes["gfa_mediodeinscripcionid"] = new EntityReference("gfa_catalogodemedios", MedioIdArea);

                            /*JER 14 Marzo 2014: Se actualiza fecha de solicitud igual a la de la creación, al dar de alta directamente (No Internet)*/
                            ActSocio.Attributes["gfa_fechasolicitud"] = DateTime.Now.ToLocalTime();
                        }
                    }
                    /*JER 13-Marzo-2014 - Si la el medio de inscripción es FACEBOOK o PORTAL WEB, no aplica actualización de medio de inscripción en base al área */

                    ActSocio.Attributes["gfa_idsocio"] = GfaIdSocio;
                    ActSocio.Attributes["gfa_idtarjeta"] = NumTar;
                    ActSocio.Attributes["gfa_nip"] = Nip;
                    /*Seteamos Fecha de Alta, Miembro Desde*/
                    ActSocio.Attributes["gfa_fechadealta"] = DateTime.Now.ToLocalTime();

                    /*Ejecutamos la actualización */
                    Servicio.Update(ActSocio);


                    /*19 Marzo 2014 JER: Se agrega código para realizar historial de cambios  */
                    MotivoCambio = "SE VALIDÓ LA INFORMACIÓN DEL SOCIO. SE PROCEDE CON LA INSCRIPCIÓN. MENSAJE AUTOMÁTICO CREADO POR CRM";
                    /*Si es ALTA en Siempre Plus*/
                    if (EstadoSocio.Equals(223060003) && EsSocioPlus)
                    {
                        MetodosFes.CreaHistorial("INSCRIPCION", MotivoCambio, EstadoSocio, IdSocio, Usr, EsSocioPlus);
                    }
                    /*Si es Alta en Socio Empresario*/
                    if (EstadoSocio.Equals(223060000) && !EsSocioPlus)
                    {
                        MetodosFes.CreaHistorial("INSCRIPCION", MotivoCambio, EstadoSocio, IdSocio, Usr, EsSocioPlus);
                    }
                }

                // Se verifican Promociones Vigentes siempre y cuando ya el estado sea ALTA*** 
                if (IdSocio != Guid.Empty)
                {
                    /*JER 3 ABRIL Si el estado es diferente de cambio de kid a Plus (Socio Plus) , entonces se otorgan km por ppromocion*/
                    if (EstadoSocio != 223060002)
                        VerificaPromociones(IdSocio, EsSocioPlus);
                }
            }

            /*19 Marzo 2014 JER: Se agrega código para realizar historial de cambios  */
            /*Si es PENDIENTE DE VALIDACION */
            MotivoCambio = "CREACIÓN DE SOLICITUD POR INTERNET (PORTAL WEB O FACEBOOK). MENSAJE AUTOMATICO GENERADO POR DYNAMICS CRM.";
            if (EstadoSocio.Equals(1))
            {
                MetodosFes.CreaHistorial("SOLICITUD DE INSCRIPCION", MotivoCambio, EstadoSocio, IdSocio, Usr, EsSocioPlus);
            }
        }

        #endregion

        #region # Método Verifica Promociones Final

        public void VerificaPromociones(Guid IdSocio, bool EsPlus)
        {
            Guid TipoSocioId = Guid.Empty;
            Guid TipoMedioId = Guid.Empty;
            Guid TipoMovId = Guid.Empty;

            Entity SocioPlus = null;

            /*Mandamos el objeto del WCF de organización a la clase de la promoción */
            Promociones Promocion = new Promociones(Servicio);

            if (EsPlus)
                // Recuperamos los datos del registro por el GUID del contacto
                SocioPlus = Servicio.Retrieve("contact", IdSocio, new ColumnSet("gfa_tipodesocioid", "gfa_mediodeinscripcionid"));
            else // Si no es Plus, es corporativo
                // Recuperamos los datos del registro por el GUID de la cuenta
                SocioPlus = Servicio.Retrieve("account", IdSocio, new ColumnSet("gfa_tipodesocioid", "gfa_mediodeinscripcionid"));

            /*Recuperamos el Guid el Tipo de Socio*/
            if (MetodosFes.ExisteAtributo("gfa_tipodesocioid", SocioPlus))
                Promocion.TipoSocio = ((EntityReference)SocioPlus.Attributes["gfa_tipodesocioid"]).Id.ToString();

            /*Recuperamos el Guid del tipo de Medio */
            if (MetodosFes.ExisteAtributo("gfa_mediodeinscripcionid", SocioPlus))
                Promocion.TipoMedio = ((EntityReference)SocioPlus.Attributes["gfa_mediodeinscripcionid"]).Id.ToString();

            /*Recuperamos el Guid del tipo de Movimiento */
            TipoMovId = MetodosFes.RecuperaGuidMovimiento("INS");
            if (TipoMovId != Guid.Empty)
                Promocion.TipoMovimiento = TipoMovId.ToString();

            if (IdSocio != Guid.Empty)
            {
                Promocion.Socioid = IdSocio.ToString();
                Promocion.Fecha = DateTime.Now.ToLocalTime();
                Promocion.RevisaPromocion();
            }

        }

        #endregion

        #region # Método para Verificar Promos Vigentes ***** ANTERIOR ****
        private void VerificaPromocionesVigentes(Guid SocioId, Entity Soci, bool EsSocioPlus)
        {
            string ClaveJustMov = "KMP";

            int EstadoSocio = 0;

            if (MetodosFes.ExisteAtributo("statuscode", Soci))
                EstadoSocio = ((OptionSetValue)Soci.Attributes["statuscode"]).Value;


            /*Se prepara Registro de creación Kms Extra */
            Entity KmExtra = new Entity("gfa_extrakm");
            /* Relacionamos al Socio en Cuestion */
            /*Si es Socio Plus*/
            if (EsSocioPlus)
            {
                KmExtra.Attributes["gfa_socioid"] = new EntityReference("contact", SocioId);
                KmExtra.Attributes["gfa_kmextras"] = 500;
            }
            else /*Si es Corporativo*/
            {
                KmExtra.Attributes["gfa_empresaid"] = new EntityReference("account", SocioId);
                KmExtra.Attributes["gfa_kmextras"] = 1000;
            }

            KmExtra.Attributes["gfa_motivo"] = "PUNTOS POR PROMOCION DE INSCRIPCION";
            /* Observaciones: El registro fue creado de manera automática pero Dynamics CRM para abonar los kilómetros retorno al Socio*/
            KmExtra.Attributes["gfa_observaciones"] = "Kilómetros generados automáticamente por Dynamics CRM. Promoción por Inscripción.";

            /* Justificación de Movimiento */
            if (MetodosFes.RecuperaGuidJustMov(ClaveJustMov) != Guid.Empty)
            {
                KmExtra.Attributes["gfa_justificaciondemovimientoid"] = new EntityReference("gfa_justmov", MetodosFes.RecuperaGuidJustMov(ClaveJustMov));
            }


            KmExtra.Attributes["gfa_kmpromocion"] = true;
            KmExtra.Attributes["gfa_promocionid"] = new EntityReference("gfa_promociones", new Guid("D9375DA4-AF8A-E311-AEAB-0050568C0F91")); //promocion alta de Prueba  Portal Web** sólo simualcion
            KmExtra.Attributes["statuscode"] = new OptionSetValue(223060002); // JER 3 ABRIL 2014 Libera Km Extra

            /* Realizamos la creación de Los kilómetros Extra */
            /* Si el Estado del Socio Plus es Alta */
            if (EsSocioPlus)
            {
                if (EstadoSocio.Equals(223060003))
                {
                    Servicio.Create(KmExtra);
                }
            }
            else /*Si el Socio Corporativo está en ALTA*/
            {
                if (EstadoSocio.Equals(223060000))
                {
                    Servicio.Create(KmExtra);
                }
            }
        }
        #endregion


    }

    /// <summary>
    /// Autor: Julio Esquivel 
    /// Fecha Enero 2014
    /// Descripción: Entra al momento de dar clic en Botón Kid a Siempre Plus. Sólo para actualizar estado anterior y Fecha de Cambio.
    /// Mensaje: Update; Attributes: gfa_tipodesocioid; Entidad: Contact; Pipeline: Post-Operation
    /// Versión 1.0
    /// </summary>
    public class ConvierteKid : IPlugin
    {
        // Variables Publicas
        public Entity Entidad = null;
        public IOrganizationService Servicio;

        public void Execute(IServiceProvider ProveedorServicio)
        {
            try
            {
                //Obtenemos el Contexto de ejecución del Plugin
                IPluginExecutionContext Contexto = (IPluginExecutionContext)ProveedorServicio.GetService(typeof(IPluginExecutionContext));

                // Validamos que exista un objeto de tipo Entity
                ValidaContexto(Contexto, ProveedorServicio);
                // Consumimos el Servicio de Organización                
                Servicio = OrganizationServiceCrm.ObtenerServicioCallingUser(Contexto, ProveedorServicio);
                // Pasamos Objeto de Servicio a los métodos FesXrm
                MetodosFes InicializaServicio = new MetodosFes(Servicio);

                // Validamos que la entidad realmente sean Socios Siempre Plus
                if (Contexto.PrimaryEntityName.Equals("contact"))
                {
                    if (Contexto.MessageName.Equals("Update"))
                    {
                        // Recuperamos los datos del registro por el GUID del Socio
                        Entity Socio = Servicio.Retrieve("contact", Contexto.PrimaryEntityId, new ColumnSet("gfa_tipodesocioid", "statuscode", "gfa_idtarjeta", "gfa_idsocio"));
                        // Se manda llamar método de conversión de Socio
                        ConvierteSocioKid(Contexto.UserId, Contexto.PrimaryEntityId, Socio);
                    }
                }
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw new InvalidPluginExecutionException("Siempre Plus ERROR Convierte Socio Kid. " + ex.Message);
            }
        }


        #region # Método de validación del Contexto que recibe el Plugin
        private Entity ValidaContexto(IPluginExecutionContext Context, IServiceProvider Prov_Servicio)
        {
            if (Context.InputParameters.Contains("Target") && Context.InputParameters["Target"] is Entity)
                Entidad = (Entity)Context.InputParameters["Target"];

            return Entidad;
        }
        #endregion

        #region # Método para realizar la conversión de Kid a Socio plus
        private void ConvierteSocioKid(Guid UsrId, Guid IdSoc, Entity Res_Soc)
        {
            int RazonEstadoAnt = 0;

            string TarjetaAnt = string.Empty;
            string IdAnt = string.Empty;
            string MotivoCambio = "EL SOCIO CUMPLIÓ LA MAYORÍA DE EDAD Y SE PROCEDIÓ CON EL CAMBIO DE TIPO EN EL PROGRAMA. MENSAJE GENERADO POR DYNAMICS CRM.";

            Guid TipoSocioid = Guid.Empty;
            string ClaveTipo = string.Empty;
            Entity ResCatTipo = null;

            // Validamos que el cambio nos traiga el Guid del tipo de Socio
            if (MetodosFes.ExisteAtributo("gfa_tipodesocioid", Res_Soc))
                TipoSocioid = ((EntityReference)Res_Soc.Attributes["gfa_tipodesocioid"]).Id;

            // Validamos si el resultados trae el campo de razón para el estado y lo guardamos como Estado anterior
            if (MetodosFes.ExisteAtributo("statuscode", Res_Soc))
                RazonEstadoAnt = ((OptionSetValue)Res_Soc.Attributes["statuscode"]).Value;

            // Validamos si el resultados trae el campo de numero de tarjeta
            if (MetodosFes.ExisteAtributo("gfa_idtarjeta", Res_Soc))
                TarjetaAnt = (string)Res_Soc.Attributes["gfa_idtarjeta"];

            // Validamos si el resultados traen el campo de numero de Socio ID
            if (MetodosFes.ExisteAtributo("gfa_idsocio", Res_Soc))
                IdAnt = (string)Res_Soc.Attributes["gfa_idsocio"];


            // Recuperamos la clave abreviada del Tipo de Socio, en este caso SP, por ser conversion
            ResCatTipo = Servicio.Retrieve("gfa_tiposocios", TipoSocioid, new ColumnSet("gfa_id"));

            // Recuperamos la clave del tipo de Socio
            if (MetodosFes.ExisteAtributo("gfa_id", ResCatTipo))
                ClaveTipo = (string)ResCatTipo.Attributes["gfa_id"];

            // Validamos que sea un valor valido
            if (ClaveTipo != "")
            {
                // Verificamos que sea SP
                if (ClaveTipo.Equals("SP"))
                {
                    /* Se actualiza la fecha por ultimo cambio de estado */
                    /* Debe actualizar el estado del Socio a Alta por Cambio de Categoria */
                    /* Debe actualizar el estado del Socio anterior a Alta  */
                    Entity Socio_Act = new Entity("contact");
                    Socio_Act.Attributes["contactid"] = IdSoc;
                    Socio_Act.Attributes["statuscode"] = new OptionSetValue(223060002); // Alta por cambio de Tipo
                    Socio_Act.Attributes["gfa_estadoanterior"] = new OptionSetValue(CatalogoEstadoAnterior(RazonEstadoAnt));
                    Socio_Act.Attributes["gfa_fechacambioestado"] = DateTime.Now.Date.ToLocalTime();
                    Socio_Act.Attributes["gfa_anteriortarjeta_kid"] = TarjetaAnt;
                    Socio_Act.Attributes["gfa_anteriorid_kid"] = IdAnt;

                    Servicio.Update(Socio_Act);

                    /*JER 24 MARZO : Historial de Cambios*/
                    /*Si ya se realizó el cambio de Kid a Plus */
                    //223060002 (ALTA POR CAMBIO DE TIPO)
                    MetodosFes.CreaHistorial("CONVERSION KID A PLUS", MotivoCambio, 223060002, IdSoc, UsrId, true);

                    #region Se manda llamar el Plugin de GenTarjetaIdNip para que entre el consecutivo
                    /*Plugin: Genera nuevo consecutivo para tipo de Socio Siempre Plus */
                    /*Plugin: Genera nuevo Número de tarjeta */
                    /*Plugin: Genera nuevo NIP */
                    /*Plugin: Se guardan como historico los anteriores datos de tarjeta, ID y NIP */
                    #endregion
                }
            }

        }
        #endregion

        #region # Método para traducir Catálogo de Estado Actual con Estado anterior de un Socio Plus

        private int CatalogoEstadoAnterior(int Valor)
        {
            int Devuelve = -1;
            switch (Valor)
            {
                case 1: Devuelve = 223060000;
                    break;

                case 223060003: Devuelve = 223060001;
                    break;

                case 223060002: Devuelve = 223060002;
                    break;

                case 223060005: Devuelve = 223060003;
                    break;

                case 223060006: Devuelve = 223060004;
                    break;

                case 2: Devuelve = 223060005;
                    break;

                case 223060004: Devuelve = 223060006;
                    break;
            }
            return Devuelve;
        }

        #endregion

    }

    /// <summary>
    /// Autor: Julio Esquivel 
    /// Fecha Enero 2014
    /// Descripción: Entra al momento de dar clic en Botón Dar de Baja en Socio Siempre Plus
    /// Mensaje: SetStateDynamicEntity; Entidad: contact; Pipeline: Pre-operation
    /// Versión 1.0
    /// </summary>
    public class BajaStateCode : IPlugin
    {
        // Variables Publicas        
        public IOrganizationService Servicio;

        public void Execute(IServiceProvider ProveedorServicio)
        {
            try
            {
                //Obtenemos el Contexto de ejecución del Plugin
                IPluginExecutionContext Contexto = (IPluginExecutionContext)ProveedorServicio.GetService(typeof(IPluginExecutionContext));

                // Consumimos el Servicio de Organización   // Administrador CRM GFA PROD       
                Servicio = OrganizationServiceCrm.ObtenerServicioUser(new Guid("51334340-C8FA-E211-B833-0050568C6FB3"), ProveedorServicio);
                // Pasamos Objeto de Servicio a los métodos FesXrm
                MetodosFes InicializaServicio = new MetodosFes(Servicio);

                //El evento del Plugin que se ejecuta cuando cambia el estado de registro principal
                if (Contexto.InputParameters.Contains("EntityMoniker") && Contexto.InputParameters["EntityMoniker"] is EntityReference)
                {
                    // Validamos que la entidad realmente sean Socios Siempre Plus
                    if (Contexto.PrimaryEntityName.Equals("contact"))
                    {
                        if (Contexto.MessageName.Equals("SetState") || Contexto.MessageName.Equals("SetStateDynamicEntity"))
                        {
                            if (Contexto.InputParameters.Contains("Status"))
                            {
                                int RazonEstado = 0;
                                RazonEstado = ((OptionSetValue)Contexto.InputParameters["Status"]).Value;
                                // Recuperamos los datos del registro por el GUID del Socio
                                Entity SocioRes = Servicio.Retrieve("contact", Contexto.PrimaryEntityId, new ColumnSet("statuscode", "gfa_kmdisponibles", "gfa_motivo"));
                                // Se manda llamar método de redención 
                                CreaRedencionEnBaja(Contexto.UserId, RazonEstado, Contexto.PrimaryEntityId, SocioRes);
                            }
                        }
                    }

                    // Validamos que la entidad realmente sean Socios Siempre Plus
                    if (Contexto.PrimaryEntityName.Equals("account"))
                    {
                        if (Contexto.MessageName.Equals("SetState") || Contexto.MessageName.Equals("SetStateDynamicEntity"))
                        {
                            if (Contexto.InputParameters.Contains("Status"))
                            {
                                int RazonEstado = 0;
                                RazonEstado = ((OptionSetValue)Contexto.InputParameters["Status"]).Value;
                                // Recuperamos los datos del registro por el GUID del Socio
                                Entity SocioRes = Servicio.Retrieve("account", Contexto.PrimaryEntityId, new ColumnSet("statuscode", "gfa_kmdisponibles", "gfa_motivo"));
                                // Se manda llamar método de redención 
                                ProcesoBloqueoBajaEmpresa(Contexto.UserId, RazonEstado, Contexto.PrimaryEntityId, SocioRes);
                            }
                        }
                    }
                }
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw new InvalidPluginExecutionException("Siempre Plus ERROR Cambio de Estado del registro. " + ex.Message);
            }
        }

        private void CreaRedencionEnBaja(Guid UsrId, int RazonActual, Guid IdSoc, Entity Socio)
        {
            int KmsDisponibles = 0;
            int RazonEdoAnt = 0;
            string MotivoCambio = "";
            
            string NombreJustMov = string.Empty;

            List<ListaBorrar> ParaBorrar = new List<ListaBorrar>();
            ParaBorrar.Clear();

            // Validamos si el resultados trae el campo de razón para el estado y lo guardamos como Estado anterior
            if (MetodosFes.ExisteAtributo("statuscode", Socio))
                RazonEdoAnt = ((OptionSetValue)Socio.Attributes["statuscode"]).Value;

            if (MetodosFes.ExisteAtributo("gfa_motivo", Socio))
                MotivoCambio = (string)Socio.Attributes["gfa_motivo"];

            // Si la razón para el estado es Baja 223060004 ()
            if (RazonActual.Equals(223060004))
            {

                #region Proceso Elimina Todos los movimientos menos el ultimo más reciente. En baja de Socio
                /*Recuperamos los ultimos movimientos(Actualizacion de Datos, Acumulaciones, Redenciones, Cancelaciones, Kilometros Extra)*/
               ParaBorrar = MetodosFes.GeneraListaUltMovsBorrar(IdSoc, true);

                /*Eliminamos todos los movimientos, menos el último registrado */
                if (ParaBorrar.Count > 0)
                {
                    foreach (ListaBorrar RegBorra in ParaBorrar)
                    {
                        Servicio.Delete(RegBorra.Entidad, RegBorra.Id);
                    }
                }
                #endregion

                #region  Proceso de creación Redención Por Baja

                /*Recuperar Km Disponibles */
                if (MetodosFes.ExisteAtributo("gfa_kmdisponibles", Socio))
                {
                    KmsDisponibles = (int)Socio.Attributes["gfa_kmdisponibles"];
                }

                /*Recuperamos el GUID de la Descripción de la justificacion del Movimiento de acuerdo a la clave CRE:Redencion por expiracion de Kms */
                EntityCollection JustMovs = MetodosFes.RecuperacionMultiple("gfa_justmov", new string[] { "gfa_descripcion" }, "gfa_id", "CRE", "statecode", "Active");
                if (JustMovs.Entities.Count > 0)
                {
                    foreach (Entity Justif in JustMovs.Entities)
                    {
                        if (MetodosFes.ExisteAtributo("gfa_justmovid", Justif))
                            /*Recuperamos la descripción de la Justificacion del Movimiento*/
                            NombreJustMov = (string)Justif.Attributes["gfa_descripcion"];
                    }
                }

                /*Creamos la Redencion con el Socio Siempre Plus*/
                Guid RedenCreada = Servicio.Create(MetodosFes.CreaObjRedencionPorBaja(KmsDisponibles, IdSoc, true));

                /*Recuperamos datos de la redención generada */
                Entity RedRes = Servicio.Retrieve("gfa_redencionkm", RedenCreada, new ColumnSet("gfa_consecutivo"));
             
                /*Actualizamos el nombre de la Redencion: Consecutivo + Justificacion */
                Entity Act_Reden = new Entity("gfa_redencionkm");
                Act_Reden.Attributes["gfa_redencionkmid"] = RedenCreada;
                Act_Reden.Attributes["gfa_name"] = "SP000" + " - " + NombreJustMov;
                Servicio.Update(Act_Reden);

                /*JER 24 MARZO : Historial de Cambios*/
                /*Si esta EN BAJA */
                MetodosFes.CreaHistorial("BAJA DE SOCIO", MotivoCambio, RazonActual, IdSoc, UsrId, true);

                #endregion

            }

            /* Se actualiza la fecha por ultimo cambio de estado */
            /* Debe actualizar el estado anterior del Socio.  */
            Entity Socio_Act = new Entity("contact");
            Socio_Act.Attributes["contactid"] = IdSoc;
            Socio_Act.Attributes["gfa_estadoanterior"] = new OptionSetValue(MetodosFes.CatalogoEstadoAnterior(RazonEdoAnt));
            Socio_Act.Attributes["gfa_fechacambioestado"] = DateTime.Now.Date.ToLocalTime();

            Servicio.Update(Socio_Act);

            /*JER 24 MARZO : Historial de Cambios*/
            /*Si esta BLOQUEADO */
            if (RazonActual.Equals(2))
                MetodosFes.CreaHistorial("BLOQUEO DE SOCIO", MotivoCambio, RazonActual, IdSoc, UsrId, true);

            /*JER 24 MARZO : Historial de Cambios*/
            /*Si esta DESBLOQUEADO */
            if (RazonActual.Equals(223060005))
                MetodosFes.CreaHistorial("DESBLOQUEO DE SOCIO", MotivoCambio, RazonActual, IdSoc, UsrId, true);

            /*JER 24 MARZO : Historial de Cambios*/
            /*Si esta REACTIVADO */
            if (RazonActual.Equals(223060006))
                MetodosFes.CreaHistorial("REACTIVACION DE SOCIO", MotivoCambio, RazonActual, IdSoc, UsrId, true);

        }

        private void ProcesoBloqueoBajaEmpresa(Guid UsrId, int RazonActual, Guid IdSoc, Entity Socio)
        {
            EntityCollection Miembros = null;
            int KmsDisponibles = 0;

            string NombreJustMov = string.Empty;            

            List<ListaBorrar> ParaBorrar = new List<ListaBorrar>();
            ParaBorrar.Clear();
        
            //Recuperamos tipo de Socio "MC"
            Guid TipoSocioMcId = Guid.Empty;

            TipoSocioMcId = MetodosFes.RecuperaGuidTipoSocio("MC");

            /*JER 24 MARZO : Historial de Cambios*/
            /*Si esta BLOQUEADO */
            if (RazonActual.Equals(2))
            {
                // Validamos que exista el Tipo de Socio MC
                if (TipoSocioMcId != Guid.Empty)
                {
                    /*Recuperamos sus Miembros Corporativos Activos y los Bloqueamos todos */
                    Miembros = MetodosFes.RecuperacionMultiple("contact", new string[] { "contactid", "parentcustomerid" }, "parentcustomerid", IdSoc.ToString(), "gfa_tipodesocioid", TipoSocioMcId.ToString(), "statecode", "Active");

                    if (Miembros.Entities.Count > 0)
                    {
                        foreach (Entity MC in Miembros.Entities)
                        {
                            // Actualizamos el motivo. del Bloqueo
                            Entity ActualizaSC = new Entity("contact");
                            ActualizaSC["contactid"] = (Guid)MC.Attributes["contactid"];
                            ActualizaSC["gfa_motivo"] = "MIEMBRO CORPORATIVO BLOQUEADO POR BLOQUEO DE SOCIO CORPORATIVO. MENSAJE GENERADO AUTOMATICAMENTE POR DYNAMICS CRM.";
                            Servicio.Update(ActualizaSC);
                            // Desactivamos el Miembro Corporativo, lo colocamos como bloqueado
                            MetodosFes.DesactivarRegistro(true, "contact", new Guid(MC.Attributes["contactid"].ToString()), 2);
                        }
                    }
                }
            }

            /*JER 24 MARZO : Historial de Cambios*/
            /*Si esta DESBLOQUEADO */
            if (RazonActual.Equals(223060001))
            {
                /*Recuperamos sus Miembros Corporativos Bloqueados  */
                Miembros = MetodosFes.RecuperacionMultiple("contact", new string[] { "contactid", "parentcustomerid" }, "parentcustomerid", IdSoc.ToString(), "gfa_tipodesocioid", TipoSocioMcId.ToString(), "statecode", "Inactive", "statuscode", "2");

                if (Miembros.Entities.Count > 0)
                {
                    foreach (Entity MC in Miembros.Entities)
                    {
                        // Actualizamos el motivo. del Desbloqueo
                        Entity ActualizaSC = new Entity("contact");
                        ActualizaSC["contactid"] = (Guid)MC.Attributes["contactid"];
                        ActualizaSC["gfa_motivo"] = "MIEMBRO CORPORATIVO DESBLOQUEADO POR DESBLOQUEO DE SOCIO CORPORATIVO. MENSAJE GENERADO AUTOMATICAMENTE POR DYNAMICS CRM.";
                        Servicio.Update(ActualizaSC);
                        // Activamos el Miembro Corporativo como ALTA POR DESBLOQUEO
                        MetodosFes.DesactivarRegistro(false, "contact", new Guid(MC.Attributes["contactid"].ToString()), 223060005);
                    }
                }
            }

            /*JER 24 MARZO : Historial de Cambios*/
            /*Si está en Baja */
            if (RazonActual.Equals(223060003))
            {
                /*Recuperamos sus Miembros Corporativos no importa si son activos o inactivos */
                Miembros = MetodosFes.RecuperacionMultiple("contact", new string[] { "contactid", "parentcustomerid" }, "parentcustomerid", IdSoc.ToString(), "gfa_tipodesocioid", TipoSocioMcId.ToString());

                if (Miembros.Entities.Count > 0)
                {
                    foreach (Entity MC in Miembros.Entities)
                    {
                        // Actualizamos el motivo de la baja
                        Entity ActualizaSC = new Entity("contact");
                        ActualizaSC["contactid"] = (Guid)MC.Attributes["contactid"];
                        ActualizaSC["gfa_motivo"] = "MIEMBRO CORPORATIVO EN BAJA POR BAJA DE SOCIO CORPORATIVO. MENSAJE GENERADO AUTOMATICAMENTE POR DYNAMICS CRM.";
                        Servicio.Update(ActualizaSC);
                        // Desactivamos el Miembro Corporativo, lo colocamos como en Baja
                        MetodosFes.DesactivarRegistro(true, "contact", new Guid(MC.Attributes["contactid"].ToString()), 223060004);
                    }
                }

                // Realizamos proceso de Baja en Socio Corporativo
                #region Proceso Elimina Todos los movimientos menos el ultimo más reciente. En baja de Socio
                /*Recuperamos los ultimos movimientos(Actualizacion de Datos, Acumulaciones, Redenciones, Cancelaciones, Kilometros Extra)*/
                ParaBorrar = MetodosFes.GeneraListaUltMovsBorrar(IdSoc, false);

                /*Eliminamos todos los movimientos, menos el último registrado */
                if (ParaBorrar.Count > 0)
                {
                    foreach (ListaBorrar RegBorra in ParaBorrar)
                    {
                        Servicio.Delete(RegBorra.Entidad, RegBorra.Id);
                    }
                }
                #endregion

                /*Recuperar Km Disponibles */
                if (MetodosFes.ExisteAtributo("gfa_kmdisponibles", Socio))
                {
                    KmsDisponibles = (int)Socio.Attributes["gfa_kmdisponibles"];
                }

                /*Recuperamos el GUID de la Descripción de la justificacion del Movimiento de acuerdo a la clave CRE:Redencion por expiracion de Kms */
                EntityCollection JustMovs = MetodosFes.RecuperacionMultiple("gfa_justmov", new string[] { "gfa_descripcion" }, "gfa_id", "CRE", "statecode", "Active");
                if (JustMovs.Entities.Count > 0)
                {
                    foreach (Entity Justif in JustMovs.Entities)
                    {
                        if (MetodosFes.ExisteAtributo("gfa_justmovid", Justif))
                            /*Recuperamos la descripción de la Justificacion del Movimiento*/
                            NombreJustMov = (string)Justif.Attributes["gfa_descripcion"];
                    }
                }

                /*Creamos la Redencion con el Socio Siempre Plus*/
                Guid RedenCreada = Servicio.Create(MetodosFes.CreaObjRedencionPorBaja(KmsDisponibles, IdSoc, false));

                /*Recuperamos datos de la redención generada */
                Entity RedRes = Servicio.Retrieve("gfa_redencionkm", RedenCreada, new ColumnSet("gfa_consecutivo"));
             
                /*Actualizamos el nombre de la Redencion: Consecutivo + Justificacion */
                Entity Act_Reden = new Entity("gfa_redencionkm");
                Act_Reden.Attributes["gfa_redencionkmid"] = RedenCreada;
                Act_Reden.Attributes["gfa_name"] = "SP0000" + " - " + NombreJustMov;
                Servicio.Update(Act_Reden);
            }

            /*JER 24 MARZO : Historial de Cambios*/
            /*Si esta REACTIVADO */
            if (RazonActual.Equals(223060004))
            {
                /*Recuperamos sus Miembros Corporativos En Baja y los Reactivamos todos */
                Miembros = MetodosFes.RecuperacionMultiple("contact", new string[] { "contactid", "parentcustomerid" }, "parentcustomerid", IdSoc.ToString(), "gfa_tipodesocioid", TipoSocioMcId.ToString(), "statecode", "Inactive", "statuscode", "223060004");

                if (Miembros.Entities.Count > 0)
                {
                    foreach (Entity MC in Miembros.Entities)
                    {
                        // Actualizamos el motivo. de la Reactivación
                        Entity ActualizaSC = new Entity("contact");
                        ActualizaSC["contactid"] = (Guid)MC.Attributes["contactid"];
                        ActualizaSC["gfa_motivo"] = "MIEMBRO CORPORATIVO REACTIVADO POR REACTIVACIÓN DE SOCIO CORPORATIVO. MENSAJE GENERADO AUTOMATICAMENTE POR DYNAMICS CRM.";
                        Servicio.Update(ActualizaSC);
                        // Reactivamos el Miembro Corporativo, lo colocamos como ALTA POR REACTIVACION
                        MetodosFes.DesactivarRegistro(false, "contact", new Guid(MC.Attributes["contactid"].ToString()), 223060006);
                    }
                }
            }
        }
    }


    /// <summary>
    /// Autor: Julio Esquivel 
    /// Fecha Enero 2014
    /// Descripción: Entra al momento de dar clic en Botón Actualizar Información de Actualización de Datos. Cambio de la razón para el estado del registro.
    /// Mensaje: Update; Filter Attributes: statuscode; Entidad: gfa_actualizaciondatos; Pipeline: Post-Operation
    /// Mensaje: Create; Entidad: gfa_actualizaciondatos; Pipeline: Post-Operation
    /// Versión 1.0
    /// </summary>
    public class MovActualizacion : IPlugin
    {
        // Variables Publicas        
        public IOrganizationService Servicio;

        public void Execute(IServiceProvider ProveedorServicio)
        {
            try
            {
                //Obtenemos el Contexto de ejecución del Plugin
                IPluginExecutionContext Contexto = (IPluginExecutionContext)ProveedorServicio.GetService(typeof(IPluginExecutionContext));

                // Consumimos el Servicio de Organización                
                Servicio = OrganizationServiceCrm.ObtenerServicioCallingUser(Contexto, ProveedorServicio);
                // Pasamos Objeto de Servicio a los métodos FesXrm
                MetodosFes InicializaServicio = new MetodosFes(Servicio);

                // Validamos que la entidad realmente sea la actualizacion de datos
                if (Contexto.PrimaryEntityName.Equals("gfa_actualizaciondatos"))
                {
                    ActualizaSocio(Contexto.PrimaryEntityId, Contexto.UserId);
                }
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw new InvalidPluginExecutionException("Siempre Plus ERROR: Actualización de datos. " + ex.Message);
            }
        }

        private void ActualizaSocio(Guid IdAct, Guid UsrId)
        {
            string Consec = string.Empty;
            string NomMedio = string.Empty;
            bool Inactivar = false;
            int RazonActual = 0;

            Guid SocioActId = Guid.Empty;
            Guid EmpresaId = Guid.Empty;
            Entity SocioPlus = null;
            Guid TipoMovId = Guid.Empty;
            Guid MedioId = Guid.Empty;

            /*Mandamos el objeto del WCF de organización a la clase de la promoción */
            Promociones Promocion = new Promociones(Servicio);

            /*Recuperamos el Guid del tipo de Movimiento para ser usado en las Promociones */
            TipoMovId = MetodosFes.RecuperaGuidMovimiento("ACT");

            // Atributos a recuperar del Registro de Actualización
            ColumnSet Columnas = new ColumnSet("gfa_consecutivo", "gfa_mediosid", "gfa_calle", "gfa_entrecalles1", "gfa_entrecalles2", "gfa_socioid",
                                               "gfa_numeroexterior", "gfa_numerointerior", "gfa_codigopostal", "gfa_coloniaid", "gfa_inactivaduplicados",
                                               "gfa_ciudadid", "gfa_delegacionmunicipioid", "gfa_estadoid", "gfa_paisid", "statuscode",
                                               "gfa_lada", "gfa_telefonoparticular", "gfa_telefonomovil", "emailaddress", "gfa_actualizadesdesocio",
                                               "gfa_nombre", "gfa_apellidopaterno", "gfa_apellidomaterno", "gfa_razonsocial", "gfa_rfc", "gfa_contactoprincipalid", "gfa_empresaid");

            // Actualizamos el Nombre del Registro de Acumulacion con el Consecutivo
            Entity ActualizaConsecutivo = new Entity("gfa_actualizaciondatos");

            // Recuperamos los datos del registro de Actualización
            Entity ActRes = Servicio.Retrieve("gfa_actualizaciondatos", IdAct, Columnas);

            // Consecutivo
            if (MetodosFes.ExisteAtributo("gfa_consecutivo", ActRes))
                Consec = (string)ActRes.Attributes["gfa_consecutivo"];

            // Medio dónde provino la actualización
            if (MetodosFes.ExisteAtributo("gfa_mediosid", ActRes))
            {
                NomMedio = ((EntityReference)ActRes.Attributes["gfa_mediosid"]).Name;
                MedioId = ((EntityReference)ActRes.Attributes["gfa_mediosid"]).Id;
            }

            // Validamos si la bandera que indica que proviene del Socio está activada
            if (MetodosFes.ExisteAtributo("statuscode", ActRes))
                RazonActual = ((OptionSetValue)ActRes.Attributes["statuscode"]).Value;

            /*Si existe un Socio Asociado, realizamos todo el proceso de Actualización*/
            if (MetodosFes.ExisteAtributo("gfa_socioid", ActRes))
                SocioActId = ((EntityReference)ActRes.Attributes["gfa_socioid"]).Id;

            /*Si existe un Empresa Asociada*/
            if (MetodosFes.ExisteAtributo("gfa_empresaid", ActRes))
                EmpresaId = ((EntityReference)ActRes.Attributes["gfa_empresaid"]).Id;

            /* Validamos la razon para el estado, sea Actualizar desde Filtro: 223060002*/
            /* Realizamos el proceso de actualización hacia Socio Plus */
            if (RazonActual.Equals(223060002))
            {
                // Asignamos variables 
                /*Si existe un Socio Asociado, realizamos todo el proceso de Actualización*/
                if (SocioActId != Guid.Empty)
                {
                    // Llenamos Objeto de Actualización 
                    Entity ActualizaSocio = new Entity("contact");
                    ActualizaSocio.Attributes["contactid"] = SocioActId;

                    // Datos Nombres *JER 1 ABRIL 2014
                    if (MetodosFes.ExisteAtributo("gfa_nombre", ActRes))
                        ActualizaSocio.Attributes["firstname"] = (string)ActRes.Attributes["gfa_nombre"];

                    if (MetodosFes.ExisteAtributo("gfa_apellidopaterno", ActRes))
                        ActualizaSocio.Attributes["lastname"] = (string)ActRes.Attributes["gfa_apellidopaterno"];

                    if (MetodosFes.ExisteAtributo("gfa_apellidomaterno", ActRes))
                        ActualizaSocio.Attributes["middlename"] = (string)ActRes.Attributes["gfa_apellidomaterno"];

                    // Datos de Direccion
                    if (MetodosFes.ExisteAtributo("gfa_calle", ActRes))
                        ActualizaSocio.Attributes["address1_line1"] = (string)ActRes.Attributes["gfa_calle"];

                    if (MetodosFes.ExisteAtributo("gfa_entrecalles1", ActRes))
                        ActualizaSocio.Attributes["address1_line2"] = (string)ActRes.Attributes["gfa_entrecalles1"];

                    if (MetodosFes.ExisteAtributo("gfa_entrecalles2", ActRes))
                        ActualizaSocio.Attributes["address1_line3"] = (string)ActRes.Attributes["gfa_entrecalles2"];

                    if (MetodosFes.ExisteAtributo("gfa_codigopostal", ActRes))
                        ActualizaSocio.Attributes["gfa_codigopostal"] = (string)ActRes.Attributes["gfa_codigopostal"];

                    if (MetodosFes.ExisteAtributo("gfa_numeroexterior", ActRes))
                        ActualizaSocio.Attributes["gfa_numext"] = (string)ActRes.Attributes["gfa_numeroexterior"];

                    if (MetodosFes.ExisteAtributo("gfa_numerointerior", ActRes))
                        ActualizaSocio.Attributes["gfa_numint"] = (string)ActRes.Attributes["gfa_numerointerior"];

                    if (MetodosFes.ExisteAtributo("gfa_coloniaid", ActRes))
                        ActualizaSocio.Attributes["gfa_coloniaid"] = new EntityReference("new_colonia", ((EntityReference)ActRes.Attributes["gfa_coloniaid"]).Id);

                    if (MetodosFes.ExisteAtributo("gfa_ciudadid", ActRes))
                        ActualizaSocio.Attributes["gfa_ciudadid"] = new EntityReference("new_ciudad", ((EntityReference)ActRes.Attributes["gfa_ciudadid"]).Id);

                    if (MetodosFes.ExisteAtributo("gfa_delegacionmunicipioid", ActRes))
                        ActualizaSocio.Attributes["gfa_delegacionmunicipioid"] = new EntityReference("new_delegacinymunicipio", ((EntityReference)ActRes.Attributes["gfa_delegacionmunicipioid"]).Id);

                    if (MetodosFes.ExisteAtributo("gfa_estadoid", ActRes))
                        ActualizaSocio.Attributes["gfa_estadoid"] = new EntityReference("new_estado", ((EntityReference)ActRes.Attributes["gfa_estadoid"]).Id);

                    if (MetodosFes.ExisteAtributo("gfa_paisid", ActRes))
                        ActualizaSocio.Attributes["gfa_paisid"] = new EntityReference("new_pais", ((EntityReference)ActRes.Attributes["gfa_paisid"]).Id);

                    // Datos de Contacto   
                    if (MetodosFes.ExisteAtributo("gfa_lada", ActRes))
                        ActualizaSocio.Attributes["address1_telephone2"] = (string)ActRes.Attributes["gfa_lada"];

                    if (MetodosFes.ExisteAtributo("gfa_telefonoparticular", ActRes))
                        ActualizaSocio.Attributes["telephone2"] = (string)ActRes.Attributes["gfa_telefonoparticular"];

                    if (MetodosFes.ExisteAtributo("gfa_telefonomovil", ActRes))
                        ActualizaSocio.Attributes["mobilephone"] = (string)ActRes.Attributes["gfa_telefonomovil"];

                    if (MetodosFes.ExisteAtributo("emailaddress", ActRes))
                        ActualizaSocio.Attributes["emailaddress1"] = (string)ActRes.Attributes["emailaddress"];

                    // Medio y fecha de actualizacion
                    if (MetodosFes.ExisteAtributo("gfa_mediosid", ActRes))
                        ActualizaSocio.Attributes["gfa_medioactualizacionid"] = new EntityReference("gfa_catalogodemedios", ((EntityReference)ActRes.Attributes["gfa_mediosid"]).Id);

                    ActualizaSocio.Attributes["gfa_fechaactualizaciondatos"] = DateTime.Now.Date.ToLocalTime();

                    /*Importante para no realizar un bucle de actualizaciones, con esto, el Socio sabe que la actualización proviene desde el Filtro */
                    ActualizaSocio.Attributes["gfa_actualizadodesdefiltro"] = true;

                    /*JER ABRIL 30* Actualizamos el usuario que realizó la actualización desde el filtro */
                    ActualizaSocio.Attributes["gfa_usuarioid"] = new EntityReference("systemuser", UsrId);

                    // Realizamos la actualización
                    Servicio.Update(ActualizaSocio);

                    /*Se desactivan aquellos registros encontrados como duplicados, en caso de existir y en caso de haber aceptado la inactivacion */
                    if (MetodosFes.ExisteAtributo("gfa_inactivaduplicados", ActRes))
                        Inactivar = (bool)ActRes.Attributes["gfa_inactivaduplicados"];

                    if (Inactivar)
                    {
                        //Recuperamos todas las Solicitudes de Actualización Activas del mismo Socio de la Actual y Diferentes a la misma.
                        EntityCollection ResSol = MetodosFes.RecuperacionMultipleNot("gfa_actualizaciondatos", new string[] { "gfa_actualizaciondatosid" }, "statecode", "Active", "gfa_actualizaciondatosid", IdAct.ToString());
                        if (ResSol.Entities.Count() > 0)
                        {
                            foreach (Entity SolAct in ResSol.Entities)
                            {
                                /*Desactivamos y Descartamos aquellos duplicados */
                                if (MetodosFes.ExisteAtributo("gfa_actualizaciondatosid", SolAct))
                                    MetodosFes.DesactivarRegistro(true, "gfa_actualizaciondatos", (Guid)SolAct.Attributes["gfa_actualizaciondatosid"], 223060000); //-Descartados-

                            }
                        }
                    }

                    /*Verificamos Promociones */
                    #region /*SE VERIFICAN PROMOCIONES*/

                    /*Recuperamos los datos del Socio */
                    SocioPlus = Servicio.Retrieve("contact", SocioActId, new ColumnSet("gfa_tipodesocioid", "gfa_mediodeinscripcionid"));

                    /*Recuperamos el Guid el Tipo de Socio*/
                    if (MetodosFes.ExisteAtributo("gfa_tipodesocioid", SocioPlus))
                        Promocion.TipoSocio = ((EntityReference)SocioPlus.Attributes["gfa_tipodesocioid"]).Id.ToString();

                    /*Recuperamos el Guid del tipo de Medio */
                    if (MedioId != Guid.Empty)
                        Promocion.TipoMedio = MedioId.ToString();

                    if (TipoMovId != Guid.Empty)
                        Promocion.TipoMovimiento = TipoMovId.ToString();

                    if (SocioActId != Guid.Empty)
                    {
                        Promocion.Socioid = SocioActId.ToString();
                        Promocion.Fecha = DateTime.Now.ToLocalTime();
                        Promocion.RevisaPromocion();
                    }

                    #endregion

                    /*Desactivamos el registro de la actualización de datos creado, con estado, -Actualizado desde Filtro-*/
                    MetodosFes.DesactivarRegistro(true, "gfa_actualizaciondatos", IdAct, 2);
                    
                    /* Agregamos al objeto de actualización al Usuario que realizó la modificación */
                    ActualizaConsecutivo.Attributes["gfa_usuarioid"] = new EntityReference("systemuser", UsrId);
                }
            }

            /* Se manda llamar desde la actualización del Socio y se crea el registro de "actualizacion de datos"*/
            /* Validamos la razon para el estado, sea Actualizar desde Socio: 223060002*/
            if (RazonActual.Equals(223060003))
            {
                /*Verificamos Promociones */
                #region /*SE VERIFICAN PROMOCIONES*/

                /*Si hay Guid de Socio Recuperamos los datos */
                if (SocioActId != Guid.Empty)
                    SocioPlus = Servicio.Retrieve("contact", SocioActId, new ColumnSet("gfa_tipodesocioid", "gfa_mediodeinscripcionid"));

                /*Si hay Guid de Empresa Recuperamos los datos */
                if (EmpresaId != Guid.Empty)
                    SocioPlus = Servicio.Retrieve("account", EmpresaId, new ColumnSet("gfa_tipodesocioid", "gfa_mediodeinscripcionid"));

                /*Recuperamos el Guid el Tipo de Socio*/
                if (MetodosFes.ExisteAtributo("gfa_tipodesocioid", SocioPlus))
                    Promocion.TipoSocio = ((EntityReference)SocioPlus.Attributes["gfa_tipodesocioid"]).Id.ToString();

                /*Recuperamos el Guid del tipo de Medio */
                if (MedioId != Guid.Empty)
                    Promocion.TipoMedio = MedioId.ToString();

                if (TipoMovId != Guid.Empty)
                    Promocion.TipoMovimiento = TipoMovId.ToString();

                if (SocioActId != Guid.Empty)
                {
                    Promocion.Socioid = SocioActId.ToString();
                    Promocion.Fecha = DateTime.Now.ToLocalTime();
                    Promocion.RevisaPromocion();
                }


                #endregion

                /*Desactivamos el registro de la actualización de datos creado, con estado, -Actualizado desde Socio-*/
                MetodosFes.DesactivarRegistro(true, "gfa_actualizaciondatos", IdAct, 223060001);

            }

            ActualizaConsecutivo.Attributes["gfa_actualizaciondatosid"] = IdAct;
            ActualizaConsecutivo.Attributes["gfa_name"] = Consec + " - ACTUALIZACION DE DATOS " + NomMedio.ToUpper();            
            Servicio.Update(ActualizaConsecutivo);

        }
    }

    /// <summary>
    /// Autor: Julio Esquivel 
    /// Fecha Enero 2014
    /// Descripción: Entra al momento de actualizar datos del Socio como Nombres, Calle, Numero, Direccion, Lada+Tel Particular, Correo, Tel Movil.
    /// Mensaje: Update; Entidad: contact (Socio Siempre Plus); Pipeline: Post-Operation
    /// Versión 1.0
    /// </summary>
    public class MovActualizacionSocio : IPlugin
    {
        // Variables Publicas        
        public IOrganizationService Servicio;

        public void Execute(IServiceProvider ProveedorServicio)
        {
            try
            {
                //Obtenemos el Contexto de ejecución del Plugin
                IPluginExecutionContext Contexto = (IPluginExecutionContext)ProveedorServicio.GetService(typeof(IPluginExecutionContext));

                // Consumimos el Servicio de Organización   // Administrador CRM GFA PROD       
                Servicio = OrganizationServiceCrm.ObtenerServicioUser(new Guid("51334340-C8FA-E211-B833-0050568C6FB3"), ProveedorServicio);
                
                // Pasamos Objeto de Servicio a los métodos FesXrm
                MetodosFes InicializaServicio = new MetodosFes(Servicio);

                Entity SocioPlus = null;

                // Definimos columnas comunes para ambos Socios 
                ColumnSet Cols = new ColumnSet("address1_line1", "address1_line2", "address1_line3", "gfa_codigopostal", "gfa_numext", "gfa_numint", "gfa_coloniaid",
                                                "gfa_ciudadid", "gfa_delegacionmunicipioid", "gfa_buscaencatalogo", "address1_county", "address1_city", "address2_county",
                                                "address1_telephone2", "telephone1", "emailaddress1", "gfa_estadoid", "gfa_paisid", "gfa_actualizadodesdefiltro");

                // Validamos que la entidad realmente sean Socios Siempre Plus
                if (Contexto.PrimaryEntityName.Equals("contact"))
                {
                    if (Contexto.MessageName.Equals("Update"))
                    {
                        // Campos no compartidos entre entidades, por lo tanto las agregamos
                        Cols.AddColumns("firstname", "lastname", "middlename", "mobilephone");
                        // Recuperamos los datos del registro por el GUID del Socio
                        SocioPlus = Servicio.Retrieve("contact", Contexto.PrimaryEntityId, Cols);
                        GeneraRegActualizacion(SocioPlus, Contexto.PrimaryEntityId, Contexto.UserId, true);
                    }
                }

                // Validamos que la entidad sea Socio Corporativo
                if (Contexto.PrimaryEntityName.Equals("account"))
                {
                    if (Contexto.MessageName.Equals("Update"))
                    {
                        // Campos no compartidos entre entidades, por lo tanto las agregamos
                        Cols.AddColumns("name", "accountnumber", "primarycontactid", "gfa_tipodesocioid");
                        // Recuperamos los datos del registro por el GUID del Socio
                        SocioPlus = Servicio.Retrieve("account", Contexto.PrimaryEntityId, Cols);
                        // Validamos que el tipo de Socio sea "CO"
                        if (MetodosFes.EsTipoSocioCorporativo(SocioPlus))
                            GeneraRegActualizacion(SocioPlus, Contexto.PrimaryEntityId, Contexto.UserId, false);
                    }
                }

            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw new InvalidPluginExecutionException("Siempre Plus ERROR Actualización de Datos. " + ex.Message);
            }
        }

        private void GeneraRegActualizacion(Entity Socio, Guid IdSoc, Guid Usr, bool EsPlus)
        {
            string Consec = string.Empty;
            string NomMedio = string.Empty;
            bool ActualiFiltro = false;
            int AreaValor = 0;
            Entity ActualizaSocio = null;

            /*Recuperamos la información del Usuario */
            Entity Usuario = Servicio.Retrieve("systemuser", Usr, new ColumnSet("gfa_area"));

            /*Realizamos el tratamiento para identificar el Area a la que pertenece*/
            if (MetodosFes.ExisteAtributo("gfa_area", Usuario))
                AreaValor = ((OptionSetValue)Usuario.Attributes["gfa_area"]).Value;

            if (EsPlus)
            {
                ActualizaSocio = new Entity("contact");
                ActualizaSocio.Attributes["contactid"] = IdSoc;
            }
            else
            {
                ActualizaSocio = new Entity("account");
                ActualizaSocio.Attributes["accountid"] = IdSoc;
            }

            // Asignamos variables 
            /*Si existe un Socio Asociado, realizamos todo el proceso de Actualización*/
            if (MetodosFes.ExisteAtributo("gfa_actualizadodesdefiltro", Socio))
            {
                /*Si la actualización es desde el filtro, no creamos registro de actualización */
                ActualiFiltro = (bool)Socio.Attributes["gfa_actualizadodesdefiltro"];

                /*Si la actualizacion no proviene desde el Filtro */
                /* No debe entrar a la creación del registro de actualización desde el Socio*/
                if (!ActualiFiltro)
                {
                    // Llenamos Objeto de Actualización 
                    Entity CreaActDatosReg = new Entity("gfa_actualizaciondatos");

                    /*Asociamos al Socio en cuestion al Registro de Actualización*/
                    if (IdSoc != Guid.Empty)
                    {
                        if (EsPlus)
                            CreaActDatosReg.Attributes["gfa_socioid"] = new EntityReference("contact", IdSoc);
                        else
                            CreaActDatosReg.Attributes["gfa_empresaid"] = new EntityReference("account", IdSoc);
                    }

                    /***********************Socio Plus **************************************************/
                    if (EsPlus)
                    {
                        // Datos de Nombre
                        if (MetodosFes.ExisteAtributo("firstname", Socio))
                            CreaActDatosReg.Attributes["gfa_nombre"] = (string)Socio.Attributes["firstname"];

                        if (MetodosFes.ExisteAtributo("lastname", Socio))
                            CreaActDatosReg.Attributes["gfa_apellidopaterno"] = (string)Socio.Attributes["lastname"];

                        if (MetodosFes.ExisteAtributo("middlename", Socio))
                            CreaActDatosReg.Attributes["gfa_apellidomaterno"] = (string)Socio.Attributes["middlename"];
                    }
                    else  /***********************Socio Corporativo ******************************************/
                    {
                        // Razon social
                        if (MetodosFes.ExisteAtributo("name", Socio))
                            CreaActDatosReg.Attributes["gfa_razonsocial"] = (string)Socio.Attributes["name"];
                        // RFC
                        if (MetodosFes.ExisteAtributo("accountnumber", Socio))
                            CreaActDatosReg.Attributes["gfa_rfc"] = (string)Socio.Attributes["accountnumber"];
                        // Contacto Principal
                        if (MetodosFes.ExisteAtributo("primarycontactid", Socio))
                            CreaActDatosReg.Attributes["gfa_contactoprincipalid"] = new EntityReference("contact", ((EntityReference)Socio.Attributes["primarycontactid"]).Id);
                    }

                    // Datos de Direccion
                    if (MetodosFes.ExisteAtributo("address1_line1", Socio))
                        CreaActDatosReg.Attributes["gfa_calle"] = (string)Socio.Attributes["address1_line1"];

                    if (MetodosFes.ExisteAtributo("address1_line2", Socio))
                        CreaActDatosReg.Attributes["gfa_entrecalles1"] = (string)Socio.Attributes["address1_line2"];

                    if (MetodosFes.ExisteAtributo("address1_line3", Socio))
                        CreaActDatosReg.Attributes["gfa_entrecalles2"] = (string)Socio.Attributes["address1_line3"];

                    if (MetodosFes.ExisteAtributo("gfa_codigopostal", Socio))
                        CreaActDatosReg.Attributes["gfa_codigopostal"] = (string)Socio.Attributes["gfa_codigopostal"];

                    if (MetodosFes.ExisteAtributo("gfa_numext", Socio))
                        CreaActDatosReg.Attributes["gfa_numeroexterior"] = (string)Socio.Attributes["gfa_numext"];

                    if (MetodosFes.ExisteAtributo("gfa_numint", Socio))
                        CreaActDatosReg.Attributes["gfa_numerointerior"] = (string)Socio.Attributes["gfa_numint"];

                    if (MetodosFes.ExisteAtributo("gfa_coloniaid", Socio))
                        CreaActDatosReg.Attributes["gfa_coloniaid"] = new EntityReference("new_colonia", ((EntityReference)Socio.Attributes["gfa_coloniaid"]).Id);

                    if (MetodosFes.ExisteAtributo("gfa_ciudadid", Socio))
                        CreaActDatosReg.Attributes["gfa_ciudadid"] = new EntityReference("new_ciudad", ((EntityReference)Socio.Attributes["gfa_ciudadid"]).Id);

                    if (MetodosFes.ExisteAtributo("gfa_delegacionmunicipioid", Socio))
                        CreaActDatosReg.Attributes["gfa_delegacionmunicipioid"] = new EntityReference("new_delegacinymunicipio", ((EntityReference)Socio.Attributes["gfa_delegacionmunicipioid"]).Id);

                    if (MetodosFes.ExisteAtributo("gfa_estadoid", Socio))
                        CreaActDatosReg.Attributes["gfa_estadoid"] = new EntityReference("new_estado", ((EntityReference)Socio.Attributes["gfa_estadoid"]).Id);

                    if (MetodosFes.ExisteAtributo("gfa_paisid", Socio))
                        CreaActDatosReg.Attributes["gfa_paisid"] = new EntityReference("new_pais", ((EntityReference)Socio.Attributes["gfa_paisid"]).Id);

                    /*Colonias Fuera de Catalogo*/
                    if (MetodosFes.ExisteAtributo("gfa_buscaencatalogo", Socio))
                        CreaActDatosReg.Attributes["gfa_buscaencatalogo"] = (bool)Socio.Attributes["gfa_buscaencatalogo"];

                    if (MetodosFes.ExisteAtributo("address1_county", Socio))
                        CreaActDatosReg.Attributes["gfa_coloniatxt"] = (string)Socio.Attributes["address1_county"];

                    if (MetodosFes.ExisteAtributo("address1_city", Socio))
                        CreaActDatosReg.Attributes["gfa_ciudadtxt"] = (string)Socio.Attributes["address1_city"];

                    if (MetodosFes.ExisteAtributo("address2_county", Socio))
                        CreaActDatosReg.Attributes["gfa_delegacionmunicipiotxt"] = (string)Socio.Attributes["address2_county"];

                    // Datos de Contacto   
                    if (MetodosFes.ExisteAtributo("address1_telephone2", Socio))
                        CreaActDatosReg.Attributes["gfa_lada"] = (string)Socio.Attributes["address1_telephone2"];

                    if (MetodosFes.ExisteAtributo("telephone1", Socio))
                        CreaActDatosReg.Attributes["gfa_telefonoparticular"] = (string)Socio.Attributes["telephone1"];

                    /************** Teléfono móvil sólo aplica para Socio Plus ***********/
                    if (EsPlus)
                    {
                        if (MetodosFes.ExisteAtributo("mobilephone", Socio))
                            CreaActDatosReg.Attributes["gfa_telefonomovil"] = (string)Socio.Attributes["mobilephone"];
                    }
                    /************** Teléfono móvil sólo aplica para Socio Plus ***********/

                    if (MetodosFes.ExisteAtributo("emailaddress1", Socio))
                        CreaActDatosReg.Attributes["emailaddress"] = (string)Socio.Attributes["emailaddress1"];

                    /*Pasamos al registro de actualizaición de datos el medio de donde se realizo la actualización*/
                    if (MetodosFes.RecuperaGuidMedioporArea(AreaValor) != Guid.Empty)
                        CreaActDatosReg.Attributes["gfa_mediosid"] = new EntityReference("gfa_catalogodemedios", MetodosFes.RecuperaGuidMedioporArea(AreaValor));

                    /*Colocamos razon para el estado como -Actualizar desde Socio (223060003)-*/
                    CreaActDatosReg.Attributes["statuscode"] = new OptionSetValue(223060003);

                    /*JER 30 ABRIL - Mandamos tambien quien realizó la actualización desde el Socio*/
                    CreaActDatosReg.Attributes["gfa_usuarioid"] = new EntityReference("systemuser", Usr);

                    // Realizamos la creacion del registro de actualización, se manda statuscode como Actualizar desde Socio
                    Servicio.Create(CreaActDatosReg);

                    /* Actualizamos fecha de actualizacion de datos */
                    ActualizaSocio.Attributes["gfa_fechaactualizaciondatos"] = DateTime.Now.Date.ToLocalTime();

                    /*JER 30 ABRIL - Actualizamos el Socio que realizó la actualización desde el Formulario */
                    ActualizaSocio.Attributes["gfa_usuarioid"] = new EntityReference("systemuser", Usr);

                    /*Actualizamos el medio de actualización relacionado al propietario*/
                    if (MetodosFes.RecuperaGuidMedioporArea(AreaValor) != Guid.Empty)
                        ActualizaSocio.Attributes["gfa_medioactualizacionid"] = new EntityReference("gfa_catalogodemedios", MetodosFes.RecuperaGuidMedioporArea(AreaValor));
                }

                /*Al final, se regres la bandera de actualizado desde a filtro a NO*/
                /* Actualizamos bandera de ActualizadoDesdeFiltro a No*/
                ActualizaSocio.Attributes["gfa_actualizadodesdefiltro"] = false;
                /*Ejecutamos Actualización*/
                Servicio.Update(ActualizaSocio);
            }
        }
    }

    /// <summary>
    /// Autor: Julio Esquivel 
    /// Fecha Enero 2014
    /// Descripción: En la creación de Kilómetros Extra, deberá de Forzarse la actualización de Kms al Socio correspondiente
    /// Mensaje: Create; Entidad: Kilómetros Extra; Pipeline: Post-Operation
    /// Mensaje: Update; FilteredAttributes: Statuscode; Entidad: Kilómetros Extra; Pipeline: Post-Operation
    /// Versión 1.0
    /// </summary>
    public class MovKmExtra : IPlugin
    {
        // Variables Publicas
        public Entity Entidad = null;
        public IOrganizationService Servicio;

        public void Execute(IServiceProvider ProveedorServicio)
        {
            try
            {
                //Obtenemos el Contexto de ejecución del Plugin
                IPluginExecutionContext Contexto = (IPluginExecutionContext)ProveedorServicio.GetService(typeof(IPluginExecutionContext));

                // Validamos que exista un objeto de tipo Entity
                ValidaContexto(Contexto, ProveedorServicio);

                // Consumimos el Servicio de Organización   // Administrador CRM GFA PROD       
                Servicio = OrganizationServiceCrm.ObtenerServicioUser(new Guid("51334340-C8FA-E211-B833-0050568C6FB3"), ProveedorServicio);
                
                // Pasamos Objeto de Servicio a los métodos FesXrm
                MetodosFes InicializaServicio = new MetodosFes(Servicio);

                // Validamos que la entidad realmente sea Km Extra
                if (Contexto.PrimaryEntityName.Equals("gfa_extrakm"))
                {
                    // Verificamos que el mensaje sea Actualizacion
                    if (Contexto.MessageName.Equals("Update") || Contexto.MessageName.Equals("Create"))
                    {
                        // Recuperamos los datos del registro de Km Extra por el Guid
                        Entity KmExtReg = Servicio.Retrieve("gfa_extrakm", Contexto.PrimaryEntityId, new ColumnSet("gfa_socioid", "gfa_empresaid", "gfa_kmextras", "gfa_justificaciondemovimientoid", "gfa_consecutivo", "statuscode"));

                        // Validamos si el valor de la razon para el estado del registro es REALIZAR KM EXTRA (223060002)
                        if (MetodosFes.ExisteAtributo("statuscode", KmExtReg))
                        {
                            if (((OptionSetValue)KmExtReg.Attributes["statuscode"]).Value == 223060002)
                            {
                                // Se manda llamar método Actualización de Kms 
                                ActualizaKm(Contexto.PrimaryEntityId, KmExtReg);
                            }
                            else // Si no es el estado esperado, entonces no se realiza nada
                                return;
                        }
                    }
                }
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw new InvalidPluginExecutionException("Siempre Plus ERROR de Kilómetros Extra. " + ex.Message);
            }
        }

        #region # Método de validación del Contexto que recibe el Plugin
        private Entity ValidaContexto(IPluginExecutionContext Context, IServiceProvider Prov_Servicio)
        {
            if (Context.InputParameters.Contains("Target") && Context.InputParameters["Target"] is Entity)
                Entidad = (Entity)Context.InputParameters["Target"];

            return Entidad;
        }
        #endregion

        #region # Método para realizar la Actualización de Kms
        private void ActualizaKm(Guid IdKmExt, Entity Res_KmExt)
        {
            /*Clave para buscar Just de Mov como Kilómetros Extra*/
            string ClaveMovKmExt = "KME";
            string ClaveJustMovCompraKm = "CKM";

            /*Km asignado por el usario del programa*/
            int KmsExt = 0;

            Guid SocioId = Guid.Empty;
            Guid EmpresaId = Guid.Empty;
            Guid JustMovId = Guid.Empty;

            string Consec = string.Empty;
            string JusMovNom = string.Empty;

            // Recuperamos el Consecutivo del Registro
            if (MetodosFes.ExisteAtributo("gfa_consecutivo", Res_KmExt))
                Consec = (string)Res_KmExt.Attributes["gfa_consecutivo"];

            // Validamos que la creación tenga el Socio relacionado
            if (MetodosFes.ExisteAtributo("gfa_socioid", Res_KmExt))
                SocioId = ((EntityReference)Res_KmExt.Attributes["gfa_socioid"]).Id;

            // Validamos que la creación tenga el Socio relacionado
            if (MetodosFes.ExisteAtributo("gfa_empresaid", Res_KmExt))
                EmpresaId = ((EntityReference)Res_KmExt.Attributes["gfa_empresaid"]).Id;

            // Validamos exista un Socio Relacionado
            if (SocioId != Guid.Empty || EmpresaId != Guid.Empty)
            {
                // Validamos si existen Kms Extra para Forzar
                if (MetodosFes.ExisteAtributo("gfa_kmextras", Res_KmExt))
                    KmsExt = (int)Res_KmExt.Attributes["gfa_kmextras"];

                /*Buscamos Catalogo de la Just del Mov */
                if (MetodosFes.ExisteAtributo("gfa_justificaciondemovimientoid", Res_KmExt))
                {
                    JustMovId = ((EntityReference)Res_KmExt.Attributes["gfa_justificaciondemovimientoid"]).Id;
                    JusMovNom = ((EntityReference)Res_KmExt.Attributes["gfa_justificaciondemovimientoid"]).Name;
                }

                if (SocioId != Guid.Empty)
                {
                    /*Se afectan Kms al Socio Plus */
                    bool Resultado = MetodosFes.AfectaKilometros(MetodosFes.Socios.Plus, SocioId, KmsExt, MetodosFes.Movimiento.KmExtra, ClaveMovKmExt, JustMovId);
                    /*Se suman Importes Totales correspondientes a la Compra de Km*/
                    MetodosFes.CalculaTotalImportes(MetodosFes.Socios.Plus, SocioId, MetodosFes.Movimiento.KmExtra, ClaveJustMovCompraKm);
                }

                if (EmpresaId != Guid.Empty)
                {
                    /*Se afectan Kms al Socio Plus */
                    bool Resultado = MetodosFes.AfectaKilometros(MetodosFes.Socios.Corporativo, EmpresaId, KmsExt, MetodosFes.Movimiento.KmExtra, ClaveMovKmExt, JustMovId);
                    /*Se suman Importes Totales correspondientes a la Compra de Km*/
                    MetodosFes.CalculaTotalImportes(MetodosFes.Socios.Corporativo, EmpresaId, MetodosFes.Movimiento.KmExtra, ClaveJustMovCompraKm);
                }

                /*Actualizamos el Nombre del Registro */
                Entity Act_KmExt = new Entity("gfa_extrakm");
                Act_KmExt.Attributes["gfa_extrakmid"] = IdKmExt;
                Act_KmExt.Attributes["gfa_name"] = Consec + " - " + JusMovNom.ToUpper();
                Act_KmExt.Attributes["gfa_fechaafectakm"] = DateTime.Now.ToLocalTime();
                Servicio.Update(Act_KmExt);

                /*Desactiva Registro con operación exitosa */
                MetodosFes.DesactivarRegistro(true, "gfa_extrakm", IdKmExt, 2);
            }
        }
        #endregion
    }

    /// <summary>
    /// Autor: Julio Esquivel 
    /// Fecha Enero 2014
    /// Descripción: En la creación del Registro de Acumulación, realiza Afectación de Kilómetros
    /// Mensaje: Create; Entidad: Acumulaciones; Pipeline: Post-Operation
    /// Versión 1.0
    /// </summary>
    public class MovAcumulacion : IPlugin
    {
        // Variables Publicas
        public Entity Entidad = null;
        public IOrganizationService Servicio;

        public void Execute(IServiceProvider ProveedorServicio)
        {
            try
            {
                //Obtenemos el Contexto de ejecución del Plugin
                IPluginExecutionContext Contexto = (IPluginExecutionContext)ProveedorServicio.GetService(typeof(IPluginExecutionContext));

                // Validamos que exista un objeto de tipo Entity
                ValidaContexto(Contexto, ProveedorServicio);
                // Consumimos el Servicio de Organización                
                Servicio = OrganizationServiceCrm.ObtenerServicioCallingUser(Contexto, ProveedorServicio);
                // Pasamos Objeto de Servicio a los métodos FesXrm
                MetodosFes InicializaServicio = new MetodosFes(Servicio);

                // Validamos que la entidad realmente sean Socios Siempre Plus
                if (Contexto.PrimaryEntityName.Equals("gfa_acumulacionkm"))
                {
                    if (Contexto.MessageName.Equals("Create"))
                    {
                        // Se manda llamar método de acumulación 
                        GenAcumulacion(Contexto.PrimaryEntityId);
                    }
                }
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw new InvalidPluginExecutionException("Siempre Plus ERROR Acumulación de KM. " + ex.Message);
            }
        }

        #region # Método de validación del Contexto que recibe el Plugin
        private Entity ValidaContexto(IPluginExecutionContext Context, IServiceProvider Prov_Servicio)
        {
            if (Context.InputParameters.Contains("Target") && Context.InputParameters["Target"] is Entity)
                Entidad = (Entity)Context.InputParameters["Target"];

            return Entidad;
        }
        #endregion

        #region # Método para realizar la generación de la Acumulación
        private void GenAcumulacion(Guid IdAcum)
        {
            #region Asignación de variables

            Guid CategoriaId = Guid.Empty;
            Guid OrgDestId = Guid.Empty;
            Guid SocioId = Guid.Empty;
            Guid EmpresaId = Guid.Empty;
            Guid TipoSocioId = Guid.Empty;

            Entity ResOrgDest = null;
            double Km_double = 0.0;
            int Km = 0;
            int KmMin = 0;
            int KmBono = 0;
            int DsctoXCategoria = 0;
            int EstadoReg = 0;
            int DsctoXTipo = 0;

            int KmBono_co = 0;
            int Km_co = 0;
            int KmMin_corp = 0;
            int PorcentajeKm_Corp = 0;

            string Consec = string.Empty;
            string NomMedio = string.Empty;
            string NumServ = string.Empty;
            string ClaveJustMov = "";
            string ClaveTipoSocio = string.Empty;

            /*JER 26 JUNIO 2014 VALIDACION DE EMPRESA, si existe ParentCustomerId*/
            string NomEntidad = string.Empty;

            Guid TipoMovId = Guid.Empty;
            Guid MedioId = Guid.Empty;
            Guid JustMovId = Guid.Empty;
     
            // 3 Noviembre Ajuste Cancelación de promociones
            Guid IdkmExtPromocion = Guid.Empty;
            Guid IdkmExtAcum = Guid.Empty;

            #endregion

            /*Mandamos el objeto del WCF de organización a la clase de la promoción */
            Promociones Promocion = new Promociones(Servicio);

            /*Recuperamos el Guid del tipo de Movimiento */
            TipoMovId = MetodosFes.RecuperaGuidMovimiento("ACS");

            // Recuperamos los datos del registro de la Acumulación creada por Integración
            Entity AcumReg = Servicio.Retrieve("gfa_acumulacionkm", IdAcum, new ColumnSet("gfa_consecutivo", "gfa_origendestinoid", "gfa_socioid", "gfa_empresaid", "gfa_categoriaid", "gfa_medioid", "gfa_numerodeservicio", "gfa_justificaciondemovimientoid", "gfa_kmpromocion"));

            // Validamos que exista un consecutivo 
            if (MetodosFes.ExisteAtributo("gfa_consecutivo", AcumReg))
                Consec = (string)AcumReg.Attributes["gfa_consecutivo"];

            // Validamos que exista un numero de servicio para Promociones
            if (MetodosFes.ExisteAtributo("gfa_numerodeservicio", AcumReg))
                NumServ = (string)AcumReg.Attributes["gfa_numerodeservicio"];

            // Validamos que exista un Socio Relacionado
            if (MetodosFes.ExisteAtributo("gfa_medioid", AcumReg))
            {
                NomMedio = ((EntityReference)AcumReg.Attributes["gfa_medioid"]).Name;
                MedioId = ((EntityReference)AcumReg.Attributes["gfa_medioid"]).Id; // Para pasarlo a la promoción
            }

            // Validamos que exista un Socio Relacionado
            if (MetodosFes.ExisteAtributo("gfa_socioid", AcumReg))
                SocioId = ((EntityReference)AcumReg.Attributes["gfa_socioid"]).Id;

            // Validamos que exista una categoría
            if (MetodosFes.ExisteAtributo("gfa_categoriaid", AcumReg))
                CategoriaId = ((EntityReference)AcumReg.Attributes["gfa_categoriaid"]).Id;

            // Validamos que la acumulación contenga Origen Destino
            if (MetodosFes.ExisteAtributo("gfa_origendestinoid", AcumReg))
                OrgDestId = ((EntityReference)AcumReg.Attributes["gfa_origendestinoid"]).Id;

            // Validamos que la acumulación cotenga Justificación de movimiento
            if (MetodosFes.ExisteAtributo("gfa_justificaciondemovimientoid", AcumReg))
                JustMovId = ((EntityReference)AcumReg.Attributes["gfa_justificaciondemovimientoid"]).Id;

            // 3 Noviembre 2014 - Validamos si trae ID de Km Extra por Promo Asociada
            if (MetodosFes.ExisteAtributo("gfa_kmpromocion", AcumReg))
                IdkmExtAcum = ((EntityReference)AcumReg.Attributes["gfa_kmpromocion"]).Id;

            // Si existe un Socio Relacionado, asi como su categoria
            if (SocioId != Guid.Empty && CategoriaId != Guid.Empty)
            {
                // Recuperamos el Registro del Origen Destino Relacionado
                ResOrgDest = Servicio.Retrieve("gfa_catalogoorigendestino", OrgDestId, new ColumnSet("gfa_kilometros", "statecode"));

                /*Se van recuperar sólo aquellos Origenes - Destino Activos */
                if (MetodosFes.ExisteAtributo("statecode", ResOrgDest))
                    EstadoReg = ((OptionSetValue)ResOrgDest.Attributes["statecode"]).Value;

                /*Se valida que el Origen - Destino estén Activos, en caso contrario, no se realiza nada */
                if (EstadoReg.Equals(0))
                {
                    // Recuperamos los kilómetros para el origen destino de la acumulación
                    if (MetodosFes.ExisteAtributo("gfa_kilometros", ResOrgDest))
                        Km = (int)ResOrgDest.Attributes["gfa_kilometros"];

                    // Validamos los Kms del Origen Destino Obtenido
                    if (Km > 0)
                    {
                        /*Si es Siempre Plus, Kid o Miembro Corporativo */
                        /*Recuperamos los datos del tipo relacionado a la Acumulación */
                        Entity SocioPlus = Servicio.Retrieve("contact", SocioId, new ColumnSet("gfa_tipodesocioid", "gfa_mediodeinscripcionid", "parentcustomerid"));

                        if (MetodosFes.ExisteAtributo("parentcustomerid", SocioPlus))
                        {
                            /* JER 26 JUNIO 2014 Validamos el nombre de la entidad para saber si es una empresa o un responsable Kid*/
                            NomEntidad = ((EntityReference)SocioPlus.Attributes["parentcustomerid"]).LogicalName;

                            if (NomEntidad.Equals("acccount"))
                                EmpresaId = ((EntityReference)SocioPlus.Attributes["parentcustomerid"]).Id;
                        }

                        if (MetodosFes.ExisteAtributo("gfa_tipodesocioid", SocioPlus))
                        {
                            // Recuperamos el Guid del Tipo de Socio
                            TipoSocioId = ((EntityReference)SocioPlus.Attributes["gfa_tipodesocioid"]).Id;
                            // Consultamos la tabla del Tipo de Socio, siempre y cuando contenga datos
                            if (TipoSocioId != Guid.Empty)
                            {
                                Entity TipoSocio = Servicio.Retrieve("gfa_tiposocios", TipoSocioId, new ColumnSet("gfa_kmsminimos", "gfa_porcentaje", "gfa_id"));

                                // Recuperamos el porcentaje Otorgado
                                if (MetodosFes.ExisteAtributo("gfa_porcentaje", TipoSocio))
                                    DsctoXTipo = (int)TipoSocio.Attributes["gfa_porcentaje"];

                                // Recuperamos la Clave del Tipo de Socio
                                if (MetodosFes.ExisteAtributo("gfa_id", TipoSocio))
                                    ClaveTipoSocio = (string)TipoSocio.Attributes["gfa_id"];

                                // Recuperamos los km minimos requeridos
                                if (MetodosFes.ExisteAtributo("gfa_kmsminimos", TipoSocio))
                                {
                                    KmMin = (int)TipoSocio.Attributes["gfa_kmsminimos"];

                                    /* Se verifica la Categoría */
                                    Entity Categoria = Servicio.Retrieve("gfa_catalogocategorias", CategoriaId, new ColumnSet("gfa_descuento"));
                                    /* Se obtiene el Porcentaje de Descuento */
                                    if (MetodosFes.ExisteAtributo("gfa_descuento", Categoria))
                                    {
                                        DsctoXCategoria = (int)Categoria.Attributes["gfa_descuento"];
                                        // Obtenemos los kilómetros resultantes de acuerdo a la categoría
                                        Km_double = Convert.ToDouble(Km) * (Convert.ToDouble(DsctoXCategoria) / 100.0);
                                        // De acuerdo a los kilómetros por Tipo de Socio, se le aplica el descuento
                                        Km_double = Convert.ToDouble(Km) * (Convert.ToDouble(DsctoXTipo) / 100.0);
                                        // Convertimos los km a entero
                                        Km = Convert.ToInt16(Km_double);

                                        // Si los kilómetros no cumplen con los mínimos, se trunca a ellos y
                                        // ... se coloca como bono los km restantes.
                                        if (Km < KmMin)
                                        {
                                            // Aplicamos Proceso de Kms Bono por no cumplir con el minimo requerido
                                            KmBono = KmMin - Convert.ToInt16(Km);
                                            // Los kilómetros Obtenidos se igualan a los minimos
                                            Km = KmMin;
                                        }
                                    }
                                }

                                Km_double = 0.0;

                                #region Si el Socio es Miembro Corporativo, se le tiene que dar un porcentaje a la empresa a la que pertenece
                                /*Verificamos si el tipo de Socio es Miembro Corporativo */
                                if (ClaveTipoSocio.Equals("MC"))
                                {
                                    /*Recuperamos los Km minimos del Socio Corporativo y aplicamos el porcentaje que le corresponde*/
                                    EntityCollection SC = MetodosFes.RecuperacionMultiple("gfa_tiposocios", new string[] { "gfa_kmsminimos", "gfa_porcentaje" }, "statecode", "Active", "gfa_id", "CO");

                                    if (SC.Entities.Count > 0)
                                    {
                                        if (MetodosFes.ExisteAtributo("gfa_kmsminimos", SC.Entities[0]))
                                            KmMin_corp = (int)SC.Entities[0].Attributes["gfa_kmsminimos"];

                                        if (MetodosFes.ExisteAtributo("gfa_porcentaje", SC.Entities[0]))
                                            PorcentajeKm_Corp = (int)SC.Entities[0].Attributes["gfa_porcentaje"];

                                        Km_double = Convert.ToDouble(Km) * (Convert.ToDouble(PorcentajeKm_Corp) / 100.0);
                                        Km_co = Convert.ToInt16(Km_double);

                                        if (Km_co < KmMin_corp)
                                        {
                                            // Aplicamos Proceso de Kms Bono por no cumplir con el minimo requerido
                                            KmBono_co = KmMin_corp - Convert.ToInt16(Km_co);
                                            // Los kilómetros Obtenidos se igualan a los minimos
                                            Km_co = KmMin_corp;
                                        }
                                    }
                                }
                                #endregion
                            }
                        }

                        #region /* SE VERIFICAN PROMOCIONES  */

                        /*Recuperamos el Guid el Tipo de Socio*/
                        if (MetodosFes.ExisteAtributo("gfa_tipodesocioid", SocioPlus))
                            Promocion.TipoSocio = ((EntityReference)SocioPlus.Attributes["gfa_tipodesocioid"]).Id.ToString();

                        /*Recuperamos el Guid del tipo de Medio */
                        if (MedioId != Guid.Empty)
                            Promocion.TipoMedio = MedioId.ToString();

                        /*Movimiento de Acumulacion*/
                        if (TipoMovId != Guid.Empty)
                            Promocion.TipoMovimiento = TipoMovId.ToString();

                        /*Origen - Destino */
                        if (OrgDestId != Guid.Empty)
                            Promocion.OrigenDestinoid = OrgDestId.ToString();

                        /*Numero de servicio */
                        if (NumServ != string.Empty)
                            Promocion.NumerodeServicio = NumServ;

                        /*Revisamos promoción, siempre y cuando exista un Socio relacionado a la acumulación*/
                        if (SocioId != Guid.Empty)
                        {
                            Promocion.Socioid = SocioId.ToString();
                            Promocion.Fecha = DateTime.Now.ToLocalTime();
                            // 3 Nov 2014 - Ajuste Cancelacion Promociones
                            IdkmExtPromocion = Promocion.RevisaPromocion();
                        }

                        #endregion

                        /*Validamos la justificación del movimiento */
                        Entity JustMov = Servicio.Retrieve("gfa_justmov", JustMovId, new ColumnSet("gfa_id"));
                        /*Validamos que tenga clave */
                        if (MetodosFes.ExisteAtributo("gfa_id", JustMov))
                            ClaveJustMov = (string)JustMov.Attributes["gfa_id"];

                        /*Si son Puntos por Viaje */
                        if (ClaveJustMov.Equals("AA2"))
                        {
                            /*Se afectan Kms al Socio Plus */
                            MetodosFes.AfectaKilometros(MetodosFes.Socios.Plus, SocioId, KmBono, Km, MetodosFes.Movimiento.Acumulacion, "ACS");
                            /* Se manda Llamar Método de Preferencias */
                            MetodosFes.ActualizaPreferencias(SocioId);
                            /* Se manda LLamar Método para Calcular Importe de Acumulaciones para Socio Plus   */
                            MetodosFes.CalculaTotalImportes(MetodosFes.Socios.Plus, SocioId, MetodosFes.Movimiento.Acumulacion, IdAcum);

                            /*Se afectan Kms al Socio Corporativo siempre y cuando exista un GUID de Empresa relacionado al Socio */
                            if (EmpresaId != Guid.Empty)
                            {
                                MetodosFes.AfectaKilometros(MetodosFes.Socios.Corporativo, EmpresaId, KmBono_co, Km_co, MetodosFes.Movimiento.Acumulacion, "ACS");
                                /* Se manda Llamar Método de Preferencias */
                                MetodosFes.ActualizaPreferenciasCorp(EmpresaId);
                                /* Se manda LLamar Método para Calcular Importe de Acumulaciones para Socio Corporativo   */
                                MetodosFes.CalculaTotalImportes(MetodosFes.Socios.Corporativo, EmpresaId, MetodosFes.Movimiento.Acumulacion, IdAcum);
                            }
                        }

                        /*Si es Cancelación de Viaje */
                        if (ClaveJustMov.Equals("CA3"))
                        {
                            /*3 Noviembre 2014 - Recuperamos dato de KM por Promo (Si aplicó) (Desde Acumulaciones)*/
                            if (IdkmExtAcum != Guid.Empty)
                            {
                                // Le sumamos los Km de la Promoción
                                Km = Km + MetodosFes.RecuperaKmXPromo(IdkmExtAcum); // Le sumamos los KM que se le dieron por la promo, para despues quitarselos
                            }

                            /*Se le quitan Kms al Socio Plus, por haber cancelado el viaje */
                            MetodosFes.AfectaKilometros(MetodosFes.Socios.Plus, SocioId, Km, MetodosFes.Movimiento.CancelacionViaje, "CAV");
                            /* Al ser cancelación no se actualizan sus Preferencias */
                            // MetodosFes.ActualizaPreferencias(SocioId);
                            /* Se manda LLamar Método para Calcular Importe por cancelación de viaje para Socio Plus   */
                            MetodosFes.CalculaTotalImportes(MetodosFes.Socios.Plus, SocioId, MetodosFes.Movimiento.CancelacionViaje, IdAcum);

                            /*Se afectan Kms al Socio Corporativo siempre y cuando exista un GUID de Empresa relacionado al Socio */
                            if (EmpresaId != Guid.Empty)
                            {
                                // Se le quitan los kilómetros de viaje
                                MetodosFes.AfectaKilometros(MetodosFes.Socios.Corporativo, EmpresaId, Km_co, MetodosFes.Movimiento.CancelacionViaje, "CAV");
                                /* Al ser Cancelación, no se actualizan sus preferencias */
                                //MetodosFes.ActualizaPreferenciasCorp(EmpresaId);
                                /* Se manda LLamar Método para Calcular Importe por cancelación de viaje para Socio Corporativo   */
                                MetodosFes.CalculaTotalImportes(MetodosFes.Socios.Corporativo, EmpresaId, MetodosFes.Movimiento.CancelacionViaje, IdAcum);
                            }
                        }
                    }
                    else
                    {
                        // No se afecta kilometraje, al ser 0 los Kms
                    }
                }

                /* Se actualizan Kms Bono y Kms Obtenidos del Registro de Acumulación */
                Entity Acum_Act = new Entity("gfa_acumulacionkm");
                Acum_Act.Attributes["gfa_acumulacionkmid"] = IdAcum;
                Acum_Act.Attributes["gfa_kmobtenidos"] = Km;
                Acum_Act.Attributes["gfa_bonos"] = KmBono;
                Acum_Act.Attributes["gfa_name"] = Consec + " - ACUMULACION POR " + NomMedio.ToUpper();

                // 3 Noviembre 2014 -Ajuste por Cancelacion de Promos
                // Si existe la promo en Puntos por viaje la seteamos en el registro
                if (IdkmExtPromocion != Guid.Empty)                
                    // Actualizamos la promo que aplicó en el registro de las acumulaciones
                    Acum_Act.Attributes["gfa_kmpromocion"] = new EntityReference("gfa_extrakm", IdkmExtPromocion);   
                                
                // Si la promo fue encontrada en Puntos por Viaje, actualizamos el campo de km ganados
                if (IdkmExtPromocion != Guid.Empty)
                    Acum_Act.Attributes["gfa_kmganados"] = MetodosFes.RecuperaKmXPromo(IdkmExtPromocion);
                // Si la promo fue encontrada en una Cancelación de Viaje, actualizamos el campo de km ganados
                if (IdkmExtAcum != Guid.Empty)
                    Acum_Act.Attributes["gfa_kmganados"] = MetodosFes.RecuperaKmXPromo(IdkmExtAcum);

                Servicio.Update(Acum_Act);
            }
        }
        #endregion

    }

    /// <summary>
    /// Autor: Julio Esquivel 
    /// Fecha Enero 2014
    /// Descripción: En la creación del Registro de Redención, realiza Afectación de Kilómetros
    /// Mensaje: Create; Entidad: gfa_redencionkm; Pipeline: Post-Operation
    /// Versión 1.0
    /// </summary>
    public class MovRedencion : IPlugin
    {
        // Variables Publicas
        public Entity Entidad = null;
        public IOrganizationService Servicio;

        public void Execute(IServiceProvider ProveedorServicio)
        {
            try
            {
                //Obtenemos el Contexto de ejecución del Plugin
                IPluginExecutionContext Contexto = (IPluginExecutionContext)ProveedorServicio.GetService(typeof(IPluginExecutionContext));

                // Validamos que exista un objeto de tipo Entity
                ValidaContexto(Contexto, ProveedorServicio);
                // Consumimos el Servicio de Organización                
                Servicio = OrganizationServiceCrm.ObtenerServicioCallingUser(Contexto, ProveedorServicio);
                // Pasamos Objeto de Servicio a los métodos FesXrm
                MetodosFes InicializaServicio = new MetodosFes(Servicio);

                // Validamos que la entidad realmente sean Socios Siempre Plus
                if (Contexto.PrimaryEntityName.Equals("gfa_redencionkm"))
                {
                    if (Contexto.MessageName.Equals("Create"))
                    {
                        // Recuperamos los datos del registro de Redención por el GUID del Socio 
                        Entity RedReg = Servicio.Retrieve("gfa_redencionkm", Contexto.PrimaryEntityId, new ColumnSet("gfa_socioid", "gfa_empresaid", "gfa_medioid", "gfa_fechaservicio", "gfa_horaservicio", "gfa_asiento", "gfa_origendestinoid", "gfa_numerooperacion", "gfa_numerodeservicio", "gfa_numredencion",
                                                                                                                     "gfa_importeservicio", "gfa_justificaciondemovimientoid", "gfa_oficinaid", "gfa_fecharedencion", "gfa_claveexpendedor", "gfa_kmusados"));
                        // Se manda llamar método de redención 
                        GenRedencion(Contexto.PrimaryEntityId, RedReg);
                    }
                }
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM. " + ex.Message);
            }
        }

        #region # Método de validación del Contexto que recibe el Plugin
        private Entity ValidaContexto(IPluginExecutionContext Context, IServiceProvider Prov_Servicio)
        {
            if (Context.InputParameters.Contains("Target") && Context.InputParameters["Target"] is Entity)
                Entidad = (Entity)Context.InputParameters["Target"];

            return Entidad;
        }
        #endregion

        #region # Método para realizar la Redención proveniente de Integración
        private void GenRedencion(Guid IdRed, Entity RedReg)
        {
            #region Definición de variables
            // Variables Locales
            string Consec = string.Empty;
            string NomMedio = string.Empty;
            string HrServicio = string.Empty;
            string ClaveMedio = string.Empty;
            int KmRed = 0;
            int Asiento = 0;
            Guid IdSocio = Guid.Empty;
            Guid IdEmpresa = Guid.Empty;
            Guid JustMovId = Guid.Empty;
            Guid MedioId = Guid.Empty;
            // Clave para registrar Ultimo Movimiento
            string ClaveRed = "RDN";
            #endregion

            #region Validaciones previas a realizar la redención

            /* Validamos si existe Socio Relacionada */
            if (MetodosFes.ExisteAtributo("gfa_socioid", RedReg))
            {
                /*Recuperamos el Guid del Socio Relacionado */
                IdSocio = ((EntityReference)RedReg.Attributes["gfa_socioid"]).Id;

                /*Error: No se puede realizar la redención, debido a que no existe Socio Asociado, se hace RollBack a la transacción */
                if (IdSocio.Equals(Guid.Empty))
                    throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM. No hay Socio Asociado, no se puede realizar la Redención. ");
            }

            /* Validamos si existe Empresa Relacionada*/
            if (MetodosFes.ExisteAtributo("gfa_empresaid", RedReg))
            {
                /*Recuperamos el Guid del Socio Relacionado */
                IdEmpresa = ((EntityReference)RedReg.Attributes["gfa_empresaid"]).Id;

                /*Error: No se puede realizar la redención, debido a que no existe Empresa Asociada, se hace RollBack a la transacción */
                if (IdEmpresa.Equals(Guid.Empty))
                    throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM. No hay Empresa Asociada, no se puede realizar la Redención.");
            }

            #region Validaciones de datos que sólo son obligatorios cuando no provengan de Portal Web, ya que son Boletos numerados

            /*Recuperamos el GUID del medio de donde provino la Redencion */
            MedioId = ((EntityReference)RedReg.Attributes["gfa_medioid"]).Id;

            Entity Medio = Servicio.Retrieve("gfa_catalogodemedios", MedioId, new ColumnSet("gfa_id"));
            ClaveMedio = (MetodosFes.ExisteAtributo("gfa_id", Medio)) ? (string)Medio.Attributes["gfa_id"] : string.Empty;

            /*Si la clave del Medio es INTERNET O PORTAL WEB, entonces son obligatorios Fecha, Hora, Numero de Servicio, Asiento*/
            if (ClaveMedio.Equals("IN"))
            {
                /* Validamos que exista dato de Numero de servicio */
                if (!MetodosFes.ExisteAtributo("gfa_numerodeservicio", RedReg))
                    throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM (INTERNET). No hay Número de servicio asociado, no se puede realizar la Redención.");

                /* Validamos que exista dato fecha de servicio */
                if (!MetodosFes.ExisteAtributo("gfa_fechaservicio", RedReg))
                    throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM (INTERNET). No hay Fecha de Servicio asociada, no se puede realizar la Redención.");

                /* Validamos que exista dato de hora de servicio */
                if (MetodosFes.ExisteAtributo("gfa_horaservicio", RedReg))
                {
                    HrServicio = (string)RedReg.Attributes["gfa_horaservicio"];
                    if (HrServicio != null)
                        if (!MetodosFes.ValidaHorasIntegra(HrServicio))
                            throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM (INTERNET). La hora de servicio: " + HrServicio + " No tiene un formato válido. No se puede realizar la Redención.");
                }
                else
                    throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM (INTERNET). No hay dato de la Hora de servicio. No se puede realizar la Redención.");

                /* Validamos que exista dato de asiento */
                if (MetodosFes.ExisteAtributo("gfa_asiento", RedReg))
                {
                    Asiento = (int)RedReg.Attributes["gfa_asiento"];
                    if (!MetodosFes.ValidaAsientoIntegra(Asiento.ToString()))
                        throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM (INTERNET). El número de asiento: " + Asiento.ToString() + " No tiene un formato válido. No se puede realizar la Redención.");
                }
                else
                    throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM (INTERNET). No hay dato de número de asiento. No se puede realizar la Redención.");
            }
            #endregion


            /* Validamos que exista dato de Importe de Servicio */
            if (!MetodosFes.ExisteAtributo("gfa_importeservicio", RedReg))
                throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM. No hay Importe del servicio asociado, no se puede realizar la Redención.");
                    
            /* Validamos que exista dato de origen-destino */
            if (!MetodosFes.ExisteAtributo("gfa_origendestinoid", RedReg))
                throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM. No hay Origen-Destino asociado, no se puede realizar la Redención.");
        
            /* Validamos que exista dato de Numero de Operacion */
            if (!MetodosFes.ExisteAtributo("gfa_numerooperacion", RedReg))
                throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM. No hay Número de operación asociado, no se puede realizar la Redención.");
        
            /* Validamos que exista dato de Numero de Redención */
            if (!MetodosFes.ExisteAtributo("gfa_numredencion", RedReg))
                throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM. No hay Número de redención asociado, no se puede realizar la Redención.");
        
            /* Validamos que exista dato de Justificación de movimiento */
            if (!MetodosFes.ExisteAtributo("gfa_justificaciondemovimientoid", RedReg))
                throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM. No hay Justificación del Movimiento asociado, no se puede realizar la Redención.");

            /* Validamos que exista dato de Oficina de Redención */
            if (!MetodosFes.ExisteAtributo("gfa_oficinaid", RedReg))
                throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM. No hay Oficina del Movimiento asociada, no se puede realizar la Redención.");
          
            /* Validamos que exista dato de Fecha de redención */
            if (!MetodosFes.ExisteAtributo("gfa_fecharedencion", RedReg))
                throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM. No hay Fecha de redención asociada, no se puede realizar la Redención.");

            /* Validamos que exista dato de Clave Expendedor */
            if (!MetodosFes.ExisteAtributo("gfa_claveexpendedor", RedReg))
                throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM. No hay clave de expendedor asociada, no se puede realizar la Redención.");

            #endregion

            #region Se afectan los kilómetros, una vez validado que toda la información que se envía por integración es correcta
            // Verificamos que el registro creado contenga los kilómetros usados
            if (MetodosFes.ExisteAtributo("gfa_kmusados", RedReg))
            {
                /*Recuperamos los Kilómetros Redimidos */
                KmRed = (int)RedReg.Attributes["gfa_kmusados"];

                /*Recuperamos el Nombre del medio de donde provino la Redencion */
                NomMedio = ((EntityReference)RedReg.Attributes["gfa_medioid"]).Name;

                /*Recuperamos la Justificación del movimiento, para validar si es una redención por expiración*/
                JustMovId = ((EntityReference)RedReg.Attributes["gfa_justificaciondemovimientoid"]).Id;

                /*Recuperamos el Número de Redención para concatenerlo en el Nombre del Registro */
                Consec = (string)RedReg.Attributes["gfa_numredencion"];

                Entity Red_Act = new Entity("gfa_redencionkm");
                Red_Act.Attributes["gfa_redencionkmid"] = IdRed;
                Red_Act.Attributes["gfa_name"] = Consec + " - REDENCION POR INTEGRACION " + NomMedio.ToUpper();
                Servicio.Update(Red_Act);

                if (IdSocio != Guid.Empty)
                {
                    /* Realizamos el recalculo de kilómetros, Actualizamos el ultimo movimiento, así como la fecha */
                    bool Exito = MetodosFes.AfectaKilometros(MetodosFes.Socios.Plus, IdSocio, KmRed, MetodosFes.Movimiento.Redencion, JustMovId, ClaveRed);
                    /*Error: El Socio no Cuenta con el kilometraje Necesario para realizar la acción*/
                    if (!Exito)
                        throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM. El Socio no cuenta con los kilómetros necesarios para realizar la redención.");

                    /* Se manda Llamar Método de Preferencias */
                    MetodosFes.ActualizaPreferencias(IdSocio);

                    /* Se manda LLamar Método para Calcular Importe de Acumulaciones   */
                    MetodosFes.CalculaTotalImportes(MetodosFes.Socios.Plus, IdSocio, MetodosFes.Movimiento.Redencion, IdRed);
                }

                if (IdEmpresa != Guid.Empty)
                {
                    /* Realizamos el recalculo de kilómetros, Actualizamos el ultimo movimiento, así como la fecha */
                    bool Exito = MetodosFes.AfectaKilometros(MetodosFes.Socios.Corporativo, IdEmpresa, KmRed, MetodosFes.Movimiento.Redencion, JustMovId, ClaveRed);
                    /*Error: El Socio no Cuenta con el kilometraje Necesario para realizar la acción*/
                    if (!Exito)
                        throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM. El Socio Corporativo no cuenta con los kilómetros necesarios para realizar la redención.");

                    /* Se manda Llamar Método de Preferencias */
                    MetodosFes.ActualizaPreferenciasCorp(IdEmpresa);

                    /* Se manda LLamar Método para Calcular Importe de Acumulaciones   */
                    MetodosFes.CalculaTotalImportes(MetodosFes.Socios.Corporativo, IdEmpresa, MetodosFes.Movimiento.Redencion, IdRed);
                }

            }
            else
            {
                /*Error: No se puede realizar la redención, debido a que no existen Km utilizados, se hace RollBack a la transacción */
                throw new InvalidPluginExecutionException("Siempre Plus ERROR Redención de KM. No hay kilómetros utilizados, no se puede realizar la Redención. ");
            }

            #endregion
        }
        #endregion
    }

    /// <summary>
    /// Autor: Julio Esquivel 
    /// Fecha Enero 2014
    /// Descripción: En la creación de la Cancelación, entra a verificar si el estado es canjeado para realizar la Cancelación
    /// Mensaje: Update; FilteredAttributes: statuscode;Entidad: gfa_cancelacionkm; Pipeline: Post-Operation
    /// Versión 1.0
    /// </summary>
    public class MovCancelaRedencion : IPlugin
    {
        // Variables Publicas
        public Entity Entidad = null;
        public IOrganizationService Servicio;

        public void Execute(IServiceProvider ProveedorServicio)
        {
            try
            {
                //Obtenemos el Contexto de ejecución del Plugin
                IPluginExecutionContext Contexto = (IPluginExecutionContext)ProveedorServicio.GetService(typeof(IPluginExecutionContext));

                // Validamos que exista un objeto de tipo Entity
                ValidaContexto(Contexto, ProveedorServicio);
                // Consumimos el Servicio de Organización   // Administrador CRM GFA PROD       
                Servicio = OrganizationServiceCrm.ObtenerServicioUser(new Guid("51334340-C8FA-E211-B833-0050568C6FB3"), ProveedorServicio);
                // Pasamos Objeto de Servicio a los métodos FesXrm
                MetodosFes InicializaServicio = new MetodosFes(Servicio);

                // Validamos que la entidad realmente sea Cancelación de Redenciones 
                if (Contexto.PrimaryEntityName.Equals("gfa_cancelacionkm"))
                {
                    // Aseguramos que el mensaje que dispara el Plugin se actualizacion
                    if (Contexto.MessageName.Equals("Update"))
                    {
                        /*Recuperamos los datos de la Cancelación en cuestión */
                        Entity CancelRed = Servicio.Retrieve("gfa_cancelacionkm", Contexto.PrimaryEntityId, new ColumnSet("gfa_kmsdevueltos", "gfa_consecutivo", "gfa_socioid", "statuscode", "gfa_redencionid", "gfa_estadoboleto", "gfa_numerooperacion", "gfa_observaciones"));

                        // Validamos si el valor de la razon para el estado del registro es CANCELAR REDENCION (223060000)
                        if (MetodosFes.ExisteAtributo("statuscode", CancelRed))
                        {
                            if (((OptionSetValue)CancelRed.Attributes["statuscode"]).Value == 223060000)
                            {
                                // Se manda llamar método para cancelar la redención 
                                CancelaRedencion(Contexto.PrimaryEntityId, CancelRed);
                            }
                            else // Si no es el estado esperado, entonces no se realiza nada
                                return;
                        }
                    }
                }
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw new InvalidPluginExecutionException("No se pudo Cancelar el Boleto Beneficio a causa de: " + ex.Message);
            }
        }

        #region # Método de validación del Contexto que recibe el Plugin
        private Entity ValidaContexto(IPluginExecutionContext Context, IServiceProvider Prov_Servicio)
        {
            if (Context.InputParameters.Contains("Target") && Context.InputParameters["Target"] is Entity)
                Entidad = (Entity)Context.InputParameters["Target"];

            return Entidad;
        }
        #endregion

        #region ***** Método para Realizar La Cancelación de la Redención, sólo aquellas provenientes de Ventas SP
        public void CancelaRedencion(Guid IdCancelacion, Entity CanRed)
        {
            /*Clave Just de Mov*/
            string ClaveJustMov = "RCT";
            /*Num de Km a devolver*/
            int KmDevuelve = 0;
            /*Numero de Cancelacion*/
            string NumCancelacion = string.Empty;
            /*Número de operacion, usado para la integracion */
            string NumOperacion = string.Empty;
            string Observaciones = string.Empty;
            string EdoCancelacion_Resp = string.Empty;
            /* Guid del Socio relacionado a la Cancelación */
            Guid SocioId = Guid.Empty;
            /*GUID de la redención asociada, sólo para desactivarla en caso de todo ok*/
            Guid IdReden = Guid.Empty;

            //Agregamos la configuración del Cliente por código          
            NetTcpBinding BindingNet = new NetTcpBinding();
            BindingNet.Name = "WcfCrmGfa";
            BindingNet.CloseTimeout = System.TimeSpan.Parse("00:25:00"); ;
            BindingNet.OpenTimeout = System.TimeSpan.Parse("00:25:00"); ;
            BindingNet.ReceiveTimeout = System.TimeSpan.Parse("00:59:00");
            BindingNet.SendTimeout = System.TimeSpan.Parse("00:59:00");
            BindingNet.TransactionFlow = false;
            BindingNet.TransferMode = TransferMode.Buffered;
            BindingNet.TransactionProtocol = TransactionProtocol.OleTransactions;
            BindingNet.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
            BindingNet.ListenBacklog = 10;
            BindingNet.MaxBufferPoolSize = 524288;
            BindingNet.MaxBufferSize = 2147483647;
            BindingNet.MaxConnections = 10;
            BindingNet.MaxReceivedMessageSize = 2147483647;

            BindingNet.ReaderQuotas.MaxDepth = 32;
            BindingNet.ReaderQuotas.MaxStringContentLength = 8192;
            BindingNet.ReaderQuotas.MaxArrayLength = 16384;
            BindingNet.ReaderQuotas.MaxBytesPerRead = 4096;
            BindingNet.ReaderQuotas.MaxNameTableCharCount = 16384;

            BindingNet.ReliableSession.Enabled = false;
            BindingNet.ReliableSession.Ordered = true;
            BindingNet.ReliableSession.InactivityTimeout = System.TimeSpan.Parse("00:10:00");

            BindingNet.Security.Mode = SecurityMode.None;
            BindingNet.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
            BindingNet.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;
            BindingNet.Security.Message.ClientCredentialType = MessageCredentialType.Windows;

            EndpointAddress endPointAddress = new EndpointAddress("net.tcp://200.34.32.32/WcfCrmGfa/WcfCrmGfa.svc/WcfCrmGfa");

            // Instanciamos el objeto del servicio
            WcfCrmGfaClient Cliente = new WcfCrmGfaClient(BindingNet, endPointAddress);

            /*Objeto con las propiedades de la cancelación*/
            GFACancelaBoletoAbiertoRed Sol_CancelaBol = new GFACancelaBoletoAbiertoRed();
            GFACancelaBoletoAbiertoRed Resp_CancelaBol = null;

            /* Si la cancelación tiene los 30 días validados en el formulario, se procede a verificar si el boleto fue o no utilizado */            
            int EdoBoleto = 0;

            if (MetodosFes.ExisteAtributo("gfa_estadoboleto", CanRed))
            {
                EdoBoleto = ((OptionSetValue)CanRed.Attributes["gfa_estadoboleto"]).Value;
                /* Se verifica que el estado del boleto sea Sin Canje (1) */
                
                if (EdoBoleto.Equals(1))
                {
                    /* Si el boleto no ha sido usado, entonces se procede a realizar la devolución de Km */

                    /*Recuperamos Num de operacion de la redención y Observacioens de la cancelación */
                    if (MetodosFes.ExisteAtributo("gfa_numerooperacion", CanRed))
                        NumOperacion = (string)CanRed.Attributes["gfa_numerooperacion"];
                    if (MetodosFes.ExisteAtributo("gfa_observaciones", CanRed))
                        Observaciones = (string)CanRed.Attributes["gfa_observaciones"];

                    /*Recuperamos el Guid de la redención relacionada */
                    if (MetodosFes.ExisteAtributo("gfa_redencionid", CanRed))
                        IdReden = ((EntityReference)CanRed.Attributes["gfa_redencionid"]).Id;

                    /*Se prepara Registro de creación Kms Extra */
                    Entity KmExtra = new Entity("gfa_extrakm");
                    /*Socio Relacionado a los Kilómetros Extra, se toma de la cancelación en cuestión */
                    if (MetodosFes.ExisteAtributo("gfa_socioid", CanRed))
                    {
                        SocioId = ((EntityReference)CanRed.Attributes["gfa_socioid"]).Id;
                        KmExtra.Attributes["gfa_socioid"] = new EntityReference("contact", SocioId);
                    }

                    /* Motivo: "Consecutivo"+  Justificación de Movimiento (Descripción)*/
                    if (MetodosFes.RecuperaGuidJustMov(ClaveJustMov) != Guid.Empty)
                    {
                        /*Recuperamos el nombre del Just de Movimiento*/
                        Entity JustMovRes = Servicio.Retrieve("gfa_justmov", MetodosFes.RecuperaGuidJustMov(ClaveJustMov), new ColumnSet("gfa_descripcion"));
                        KmExtra.Attributes["gfa_motivo"] = (string)JustMovRes.Attributes["gfa_descripcion"];
                    }

                    if (MetodosFes.ExisteAtributo("gfa_consecutivo", CanRed))
                        NumCancelacion = (string)CanRed.Attributes["gfa_consecutivo"];

                    /* Observaciones: El registro fue creado de manera automática pero Dynamics CRM para abonar los kilómetros retorno al Socio*/
                    KmExtra.Attributes["gfa_observaciones"] = "Registro creado automáticamente por Dynamics CRM. En relación a la Cancelación No. " + NumCancelacion;
                    if (MetodosFes.RecuperaGuidJustMov(ClaveJustMov) != Guid.Empty)
                    {
                        KmExtra.Attributes["gfa_justificaciondemovimientoid"] = new EntityReference("gfa_justmov", MetodosFes.RecuperaGuidJustMov(ClaveJustMov));
                    }

                    if (MetodosFes.ExisteAtributo("gfa_kmsdevueltos", CanRed))
                        KmDevuelve = (int)CanRed.Attributes["gfa_kmsdevueltos"];

                    KmExtra.Attributes["gfa_kmextras"] = KmDevuelve;

                    /*Mandamos la creación de Kilómetros Extra para liberarse */
                    KmExtra.Attributes["statuscode"] = new OptionSetValue(223060002);
                                                      
                    /* Se consume WCF de GFA para enviar a Taquilla notificación de que se realizó la Cancelación Correctamente */
                    /* Se envía Número de Operación , Oficina, Clave Expendedor */
                    Sol_CancelaBol.gfa_numerooperacionk__BackingField = NumOperacion;
                    Sol_CancelaBol.gfa_oficinak__BackingField = "SP";
                    Sol_CancelaBol.gfa_claveexpendedork__BackingField = "CRMEX";
                    Sol_CancelaBol.gfa_observacionesk__BackingField = Observaciones;

                    // Enviamos a cancelar la redención
                    Resp_CancelaBol = Cliente.CancelarBoletoAbiertoRedimido(Sol_CancelaBol);

                    if (Resp_CancelaBol.gfa_estadomovimientok__BackingField != null)
                        EdoCancelacion_Resp = Resp_CancelaBol.gfa_estadomovimientok__BackingField;
                                  
                    Entity ActEstadoCancelacion = new Entity("gfa_cancelacionkm");
                    ActEstadoCancelacion.Attributes["gfa_cancelacionkmid"] = IdCancelacion;
                    ActEstadoCancelacion.Attributes["gfa_estadocancelacion"] = EdoCancelacion_Resp;
                    ActEstadoCancelacion.Attributes["gfa_detallecancelacion"] = (Resp_CancelaBol.gfa_detallemovimientok__BackingField != null)? Resp_CancelaBol.gfa_detallemovimientok__BackingField: string.Empty;
                   
                    if (Resp_CancelaBol.gfa_fechacancelacionk__BackingField > DateTime.MinValue)
                        ActEstadoCancelacion.Attributes["gfa_fechacancelacion"] = Resp_CancelaBol.gfa_fechacancelacionk__BackingField;

                    ActEstadoCancelacion.Attributes["gfa_horacancelacion"] = (Resp_CancelaBol.gfa_horacancelacionk__BackingField != null)? Resp_CancelaBol.gfa_horacancelacionk__BackingField: string.Empty;;
                   
                    /* Si la respuesta es C (correcto), entonces todo se realiza sin inconvenientes */
                    if (EdoCancelacion_Resp.Equals("Correcto"))
                    {
                        // Si es correcto, entonces creamos registro de km extra                        
                        Servicio.Create(KmExtra);

                        // Actualizamos el estado del boleto a CANCELADO 
                        ActEstadoCancelacion.Attributes["gfa_estadoboleto"] = new OptionSetValue(3);
                        /* Desactivamos la redención relacionada a la cancelación en CRM  -CANCELADA- */
                        if (IdReden != Guid.Empty)
                            MetodosFes.DesactivarRegistro(true, "gfa_redencionkm", IdReden, 2);

                        /*Desactivamos el registro de la cancelación de redención creada, con estado, -Cancelacion Exitosa-*/
                        MetodosFes.DesactivarRegistro(true, "gfa_cancelacionkm", IdCancelacion, 2);
                    }
                    else ///* Si hubo problemas para cancelar al momento de recibir respuesta, se queda pendiente de validación */
                        KmExtra = null;  

                    // Actualizamos finalmente el registro de cancelación
                    Servicio.Update(ActEstadoCancelacion);
                   
                }
                else if (EdoBoleto.Equals(2))
                {
                    /*Error: El Boleto ha sido canjeado. No se puede continuar con la Cancelación de la Redención. */
                    throw new InvalidPluginExecutionException("El boleto ya ha sido CANJEADO. No se puede continuar con la Cancelación.");
                }
                else if (EdoBoleto.Equals(3))
                {
                    /*Error: El Boleto ya ha sido Cancelado. No se puede continuar con el proceso. */
                    throw new InvalidPluginExecutionException("El boleto ya ha sido CANCELADO. No se puede continuar con la Cancelación.");
                }
            }
           
        }

        #endregion
    }

    /// <summary>
    /// Autor: Julio Esquivel 
    /// Fecha Enero 2014
    /// Descripción: En la creación de la conuslta, se consume el WCF y se recupera la información del boleto
    /// Mensaje: Create; Entidad: gfa_consultaboletoredimido; Pipeline: Post-Operation
    /// Versión 1.0
    /// </summary>
    public class MovConsultaBoletoRed : IPlugin
    {
        // Variables Publicas
        public Entity Entidad = null;
        public IOrganizationService Servicio;

        public void Execute(IServiceProvider ProveedorServicio)
        {
            try
            {
                //Obtenemos el Contexto de ejecución del Plugin
                IPluginExecutionContext Contexto = (IPluginExecutionContext)ProveedorServicio.GetService(typeof(IPluginExecutionContext));

                // Validamos que exista un objeto de tipo Entity
                ValidaContexto(Contexto, ProveedorServicio);
                // Consumimos el Servicio de Organización   // Administrador CRM GFA PROD       
                Servicio = OrganizationServiceCrm.ObtenerServicioUser(new Guid("51334340-C8FA-E211-B833-0050568C6FB3"), ProveedorServicio);
                // Pasamos Objeto de Servicio a los métodos FesXrm
                MetodosFes InicializaServicio = new MetodosFes(Servicio);

                // Validamos que la entidad realmente sea Cancelación de Redenciones 
                if (Contexto.PrimaryEntityName.Equals("gfa_consultaboletoredimido"))
                {
                    // Aseguramos que el mensaje que dispara el Plugin se actualizacion
                    if (Contexto.MessageName.Equals("Create"))
                    {                       
                        // Se manda llamar método para consumir el WCF de consulta del boleto
                        ConsultaBoleto(Contexto.PrimaryEntityId);                         
                    }
                }
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw new InvalidPluginExecutionException("No se pudo consultar el boleto beneficio a causa de: " + ex.Message);
            }
        }

        #region # Método de validación del Contexto que recibe el Plugin
        private Entity ValidaContexto(IPluginExecutionContext Context, IServiceProvider Prov_Servicio)
        {
            if (Context.InputParameters.Contains("Target") && Context.InputParameters["Target"] is Entity)
                Entidad = (Entity)Context.InputParameters["Target"];

            return Entidad;
        }
        #endregion

        #region ***** Método para Realizar La consulta del boleto redimido
        public void ConsultaBoleto(Guid IdConsulta)
        {
            //Agregamos la configuración del Cliente por código          
            NetTcpBinding BindingNet = new NetTcpBinding();
            BindingNet.Name = "WcfCrmGfa";
            BindingNet.CloseTimeout = System.TimeSpan.Parse("00:25:00"); ;
            BindingNet.OpenTimeout = System.TimeSpan.Parse("00:25:00"); ;
            BindingNet.ReceiveTimeout = System.TimeSpan.Parse("00:59:00");
            BindingNet.SendTimeout = System.TimeSpan.Parse("00:59:00");
            BindingNet.TransactionFlow = false;
            BindingNet.TransferMode = TransferMode.Buffered;
            BindingNet.TransactionProtocol = TransactionProtocol.OleTransactions;
            BindingNet.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
            BindingNet.ListenBacklog = 10;
            BindingNet.MaxBufferPoolSize = 524288;
            BindingNet.MaxBufferSize = 2147483647;
            BindingNet.MaxConnections = 10;
            BindingNet.MaxReceivedMessageSize = 2147483647;

            BindingNet.ReaderQuotas.MaxDepth = 32;
            BindingNet.ReaderQuotas.MaxStringContentLength = 8192;
            BindingNet.ReaderQuotas.MaxArrayLength = 16384;
            BindingNet.ReaderQuotas.MaxBytesPerRead = 4096;
            BindingNet.ReaderQuotas.MaxNameTableCharCount = 16384;

            BindingNet.ReliableSession.Enabled = false;
            BindingNet.ReliableSession.Ordered = true;
            BindingNet.ReliableSession.InactivityTimeout = System.TimeSpan.Parse("00:10:00");

            BindingNet.Security.Mode = SecurityMode.None;
            BindingNet.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
            BindingNet.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;
            BindingNet.Security.Message.ClientCredentialType = MessageCredentialType.Windows;

            EndpointAddress endPointAddress = new EndpointAddress("net.tcp://200.34.32.32/WcfCrmGfa/WcfCrmGfa.svc/WcfCrmGfa");
                                              
            // Instanciamos el objeto del servicio
            WcfCrmGfaClient Cliente = new WcfCrmGfaClient(BindingNet, endPointAddress);

            #region Declaración de variables
            string Numoperacion = string.Empty;
            string BolRed_origendestino = string.Empty;
            string BolRed_NumServicio = string.Empty;
            DateTime BolRed_FechaRedencion = DateTime.MinValue;
            string BolRed_HoraRedencion = string.Empty;
            DateTime BolRed_FechaCanje = DateTime.MinValue;
            string BolRed_EstatusBol = string.Empty;
            string BolRed_Asiento = string.Empty;
            double BolRed_ImporteServ = 0.0;
            string BolRed_ClaveExp = string.Empty;

            Guid OrDestId = Guid.Empty;
            GFABoletoAbiertoRed Respuesta = null;
            #endregion

            // Recuperamos el Número de operación de la redención que se encuentra en la registro de la consulta
            Entity Consulta = Servicio.Retrieve("gfa_consultaboletoredimido", IdConsulta, new ColumnSet("gfa_numerooperacion"));
            Numoperacion = (MetodosFes.ExisteAtributo("gfa_numerooperacion", Consulta)) ? (string)Consulta.Attributes["gfa_numerooperacion"] : string.Empty;

            if (Numoperacion != string.Empty)
                Respuesta = Cliente.ConsultaBoletoAbiertoRedimido("SP", Numoperacion); //("SP","92742");           

            if (Respuesta != null)
            {
                /*RESPUESTA */
                BolRed_origendestino = (Respuesta.gfa_origendestinoidk__BackingField != null) ? Respuesta.gfa_origendestinoidk__BackingField : string.Empty;
                BolRed_NumServicio = (Respuesta.gfa_numeroserviciok__BackingField != null) ? Respuesta.gfa_numeroserviciok__BackingField : string.Empty;
                ///* Falta Fecha y hora de Servicio ** No se va utilizar debido a que no es muy necesario en la cancelación, ya se tiene el estado del canje */
                BolRed_FechaRedencion = Respuesta.gfa_fecharedencionk__BackingField;
                BolRed_HoraRedencion = (Respuesta.gfa_horaredencionk__BackingField != null) ? Respuesta.gfa_horaredencionk__BackingField : string.Empty;
                BolRed_FechaCanje = Respuesta.gfa_fechacanjek__BackingField;
                BolRed_EstatusBol = (Respuesta.gfa_estatusboletok__BackingField != null) ? Respuesta.gfa_estatusboletok__BackingField : string.Empty;
                BolRed_Asiento = (Respuesta.gfa_asientok__BackingField != null) ? Respuesta.gfa_asientok__BackingField : string.Empty;
                BolRed_ImporteServ = (Respuesta.gfa_importeserviciok__BackingField != 0.0) ? Respuesta.gfa_importeserviciok__BackingField : 0.0;
                BolRed_ClaveExp = (Respuesta.gfa_claveexpendedork__BackingField != null) ? Respuesta.gfa_claveexpendedork__BackingField : string.Empty;

                if (BolRed_origendestino != string.Empty)
                    OrDestId = MetodosFes.RecuperaGuidOrgDest(BolRed_origendestino);

                Entity Act_Consulta = new Entity("gfa_consultaboletoredimido");
                Act_Consulta.Attributes["gfa_consultaboletoredimidoid"] = IdConsulta;

                if (OrDestId != Guid.Empty)
                    Act_Consulta.Attributes["gfa_origendestinoid"] = new EntityReference("gfa_catalogoorigendestino", OrDestId);

                if (BolRed_NumServicio != string.Empty)
                    Act_Consulta.Attributes["gfa_numerodeservicio"] = BolRed_NumServicio;

                if (BolRed_FechaRedencion > DateTime.MinValue)
                    Act_Consulta.Attributes["gfa_fecharedencion"] = BolRed_FechaRedencion;

                if (BolRed_HoraRedencion != string.Empty)
                    Act_Consulta.Attributes["gfa_horaredencion"] = BolRed_HoraRedencion;

                if (BolRed_FechaCanje > DateTime.MinValue)
                    Act_Consulta.Attributes["gfa_fechacanje"] = BolRed_FechaCanje;

                if (MetodosFes.CatalogoEstadoBoleto(BolRed_EstatusBol) != -1)
                    Act_Consulta.Attributes["gfa_estadoboleto"] = new OptionSetValue(MetodosFes.CatalogoEstadoBoleto(BolRed_EstatusBol));

                if (BolRed_Asiento != string.Empty)
                    Act_Consulta.Attributes["gfa_asiento"] = Convert.ToInt32(BolRed_Asiento);

                if (BolRed_ImporteServ != 0)
                    Act_Consulta.Attributes["gfa_importedeservicio"] = new Money(Convert.ToDecimal(BolRed_ImporteServ));

                if (BolRed_ClaveExp != string.Empty)
                    Act_Consulta.Attributes["gfa_claveexpendedor"] = BolRed_ClaveExp;

                // Realizamos la actualización
                Servicio.Update(Act_Consulta);
            }

        }
        #endregion
    }
}
